public Loan(int legs) { legs_ = new InitializedList<List<CashFlow>>(legs); payer_ = new InitializedList<double>(legs); notionals_ = new List<double>(); legNPV_ = new InitializedList<double?>(legs); }
private void initialize() { // firstSeed is chosen based on clock() and used for the first rng ulong firstSeed = (ulong)DateTime.Now.Ticks; // (std::time(0)); MersenneTwisterUniformRng first = new MersenneTwisterUniformRng(firstSeed); // secondSeed is as random as it could be // feel free to suggest improvements ulong secondSeed = first.nextInt32(); MersenneTwisterUniformRng second = new MersenneTwisterUniformRng(secondSeed); // use the second rng to initialize the final one ulong skip = second.nextInt32() % 1000; List<ulong> init = new InitializedList<ulong>(4); init[0]=second.nextInt32(); init[1]=second.nextInt32(); init[2]=second.nextInt32(); init[3]=second.nextInt32(); rng_ = new MersenneTwisterUniformRng(init); for (ulong i=0; i<skip ; i++) rng_.nextInt32(); }
public override EndCriteria.Type minimize(Problem P, EndCriteria endCriteria) { EndCriteria.Type ecType = EndCriteria.Type.None; P.reset(); Vector x_ = P.currentValue(); currentProblem_ = P; initCostValues_ = P.costFunction().values(x_); int m = initCostValues_.size(); int n = x_.size(); Vector xx = new Vector(x_); Vector fvec = new Vector(m), diag = new Vector(n); int mode = 1; double factor = 1; int nprint = 0; int info = 0; int nfev =0; Matrix fjac = new Matrix(m, n); int ldfjac = m; List<int> ipvt = new InitializedList<int>(n); Vector qtf = new Vector(n), wa1 = new Vector(n), wa2 = new Vector(n), wa3 = new Vector(n), wa4 = new Vector(m); // call lmdif to minimize the sum of the squares of m functions // in n variables by the Levenberg-Marquardt algorithm. MINPACK.lmdif(m, n, xx, ref fvec, endCriteria.functionEpsilon(), xtol_, gtol_, endCriteria.maxIterations(), epsfcn_, diag, mode, factor, nprint, ref info, ref nfev, ref fjac, ldfjac, ref ipvt, ref qtf, wa1, wa2, wa3, wa4, fcn); info_ = info; // check requirements & endCriteria evaluation if(info == 0) throw new ApplicationException("MINPACK: improper input parameters"); //if(info == 6) throw new ApplicationException("MINPACK: ftol is too small. no further " + // "reduction in the sum of squares is possible."); if (info != 6) ecType = EndCriteria.Type.StationaryFunctionValue; //QL_REQUIRE(info != 5, "MINPACK: number of calls to fcn has reached or exceeded maxfev."); endCriteria.checkMaxIterations(nfev, ref ecType); if(info == 7) throw new ApplicationException("MINPACK: xtol is too small. no further " + "improvement in the approximate " + "solution x is possible."); if(info == 8) throw new ApplicationException("MINPACK: gtol is too small. fvec is " + "orthogonal to the columns of the " + "jacobian to machine precision."); // set problem x_ = new Vector(xx.GetRange(0, n)); P.setCurrentValue(x_); P.setFunctionValue(P.costFunction().value(x_)); return ecType; }
public AmericanExercise(Date latest, bool payoffAtExpiry) : base(Type.American, payoffAtExpiry) { dates_ = new InitializedList<Date>(2); dates_[0] = Date.minDate(); dates_[1] = latest; }
//public List<CashFlow> interestCashflows() //{ // List<CashFlow> icf = new List<CashFlow>(); // foreach (CashFlow cf in cashflows()) // { // if (cf is QLNet.FixedRateCoupon) // icf.Add(cf); // } // return icf; //} public List<CashFlow> expectedCashflows() { calcBondFactor(); List<CashFlow> expectedcashflows = new List<CashFlow>(); List<double> notionals = new InitializedList<double>(schedule_.Count); notionals[0] = notionals_[0]; for (int i = 0; i < schedule_.Count - 1; ++i) { double currentNotional = notionals[i]; double smm = SMM(schedule_[i]); double prepay = (notionals[i] * bondFactors_[i + 1]) / bondFactors_[i] * smm; double actualamort = currentNotional * (1 - bondFactors_[i + 1] / bondFactors_[i]); notionals[i + 1] = currentNotional - actualamort - prepay; // ADD CashFlow c1 = new VoluntaryPrepay(prepay, schedule_[i + 1]); CashFlow c2 = new AmortizingPayment(actualamort, schedule_[i + 1]); CashFlow c3 = new FixedRateCoupon(currentNotional, schedule_[i + 1], new InterestRate(PassThroughRate_, dCounter_, Compounding.Simple), schedule_[i], schedule_[i + 1]); expectedcashflows.Add(c1); expectedcashflows.Add(c2); expectedcashflows.Add(c3); } notionals[notionals.Count - 1] = 0.0; return expectedcashflows; }
public static List<Func<Vector, double>> multiPathBasisSystem(int dim, int order, PolynomType polynomType) { List<Func<double, double>> b = pathBasisSystem(order, polynomType); List<Func<Vector, double>> ret = new List<Func<Vector,double>>(); ret.Add((xx) => 1.0); for (int i=1; i<=order; ++i) { List<Func<Vector, double>> a = w(dim, i, polynomType, b); foreach (var iter in a) { ret.Add(iter); } } // remove-o-zap: now remove redundant functions. // usually we do have a lot of them due to the construction schema. // We use a more "hands on" method here. List<bool> rm = new InitializedList<bool>(ret.Count, true); Vector x = new Vector(dim), v = new Vector(ret.Count); MersenneTwisterUniformRng rng = new MersenneTwisterUniformRng(1234UL); for (int i=0; i<10; ++i) { int k; // calculate random x vector for (k=0; k<dim; ++k) { x[k] = rng.next().value; } // get return values for all basis functions for (k = 0; k < ret.Count; ++k) { v[k] = ret[k](x); } // find duplicates for (k = 0; k < ret.Count; ++k) { if (v.First(xx => (Math.Abs(v[k] - xx) <= 10*v[k]*Const.QL_Epsilon)) == v.First() + k) { // don't remove this item, it's unique! rm[k] = false; } } } int iter2 = 0; for (int i = 0; i < rm.Count; ++i) { if (rm[i]) { ret.RemoveAt(iter2); } else { ++iter2; } } return ret; }
public AmericanExercise(Date earliestDate, Date latestDate, bool payoffAtExpiry) : base(Type.American, payoffAtExpiry) { if (!(earliestDate <= latestDate)) throw new ApplicationException("earliest > latest exercise date"); dates_ = new InitializedList<Date>(2); dates_[0] = earliestDate; dates_[1] = latestDate; }
public override double value(double x, double y) { List<double> section = new InitializedList<double>( splines_.Count ); for (int i=0; i<splines_.Count; i++) section[i]=splines_[i].value(x,true); CubicInterpolation spline = new CubicInterpolation(this.yBegin_, this.ySize_, section, CubicInterpolation.DerivativeApprox.Spline, false, CubicInterpolation.BoundaryCondition.SecondDerivative, 0.0, CubicInterpolation.BoundaryCondition.SecondDerivative, 0.0); return spline.value(y,true); }
//! generic times /*! \note the starting time of the path is assumed to be 0 and must not be included */ public BrownianBridge(List<double> times) { size_ = times.Count; t_ = 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_); initialize(); }
public double secondDerivativeX(double x, double y) { List<double> section = new InitializedList<double>( this.zData_.columns() ); for (int i=0; i < section.Count; ++i) { section[i] = value(this.xBegin_[i], y); } return new CubicInterpolation( this.xBegin_, this.xSize_, section, CubicInterpolation.DerivativeApprox.Spline, false, CubicInterpolation.BoundaryCondition.SecondDerivative, 0.0, CubicInterpolation.BoundaryCondition.SecondDerivative, 0.0).secondDerivative(x); }
// Computes the size of the simplex public static double computeSimplexSize(InitializedList<Vector> vertices) { Vector center = new Vector(vertices[0].Count, 0); for (int i = 0; i < vertices.Count; ++i) center += vertices[i]; center *= 1 / (double)(vertices.Count); double result = 0; for (int i = 0; i < vertices.Count; ++i) { Vector temp = vertices[i] - center; result += Math.Sqrt(Vector.DotProduct(temp, temp)); } return result / (double)(vertices.Count); }
//! unit-time path public BrownianBridge(int steps) { size_ = steps; t_ = 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] = i+1; initialize(); }
public DiscretizedSwaption(Swaption.Arguments args, Date referenceDate, DayCounter dayCounter) : base(new DiscretizedSwap(args, referenceDate, dayCounter), args.exercise.type(), new List<double>()) { arguments_=args; exerciseTimes_ = new InitializedList<double>(arguments_.exercise.dates().Count); for (int i = 0; i < exerciseTimes_.Count; ++i) exerciseTimes_[i] = dayCounter.yearFraction(referenceDate, arguments_.exercise.date(i)); // Date adjustments can get time vectors out of synch. // Here, we try and collapse similar dates which could cause // a mispricing. for (int i=0; i<arguments_.exercise.dates().Count; i++) { Date exerciseDate = arguments_.exercise.date(i); for (int j = 0; j < arguments_.fixedPayDates.Count; j++) { if (withinNextWeek(exerciseDate, arguments_.fixedPayDates[j]) // coupons in the future are dealt with below && arguments_.fixedResetDates[j] < referenceDate) arguments_.fixedPayDates[j] = exerciseDate; } for (int j = 0; j < arguments_.fixedResetDates.Count; j++) { if (withinPreviousWeek(exerciseDate, arguments_.fixedResetDates[j])) arguments_.fixedResetDates[j] = exerciseDate; } for (int j = 0; j < arguments_.floatingResetDates.Count; j++) { if (withinPreviousWeek(exerciseDate, arguments_.floatingResetDates[j])) arguments_.floatingResetDates[j] = exerciseDate; } } double lastFixedPayment = dayCounter.yearFraction(referenceDate, arguments_.fixedPayDates.Last() ); double lastFloatingPayment = dayCounter.yearFraction(referenceDate, arguments_.floatingPayDates.Last()); lastPayment_ = Math.Max(lastFixedPayment,lastFloatingPayment); underlying_ = new DiscretizedSwap(arguments_, referenceDate, dayCounter); }
public void test1dLinearRegression() { //BOOST_MESSAGE("Testing 1d simple linear least-squares regression..."); /* Example taken from the QuantLib-User list, see posting * Multiple linear regression/weighted regression, Boris Skorodumov */ //SavedSettings backup; List<double> x = new InitializedList<double>(9), y = new InitializedList<double>(9); x[0] = 2.4; x[1] = 1.8; x[2] = 2.5; x[3] = 3.0; x[4] = 2.1; x[5] = 1.2; x[6] = 2.0; x[7] = 2.7; x[8] = 3.6; y[0] = 7.8; y[1] = 5.5; y[2] = 8.0; y[3] = 9.0; y[4] = 6.5; y[5] = 4.0; y[6] = 6.3; y[7] = 8.4; y[8] = 10.2; List<Func<double, double>> v = new List<Func<double, double>>(); v.Add(a => 1.0); v.Add(a => a); LinearRegression m = new LinearRegression(x, y); const double tol = 0.0002; double[] coeffExpected = new double[] { 0.9448, 2.6853 }; double[] errorsExpected = new double[] { 0.3654, 0.1487 }; for (int i = 0; i < 2; ++i) { if (Math.Abs(m.standardErrors()[i] - errorsExpected[i]) > tol) { Assert.Fail("Failed to reproduce linear regression standard errors" + "\n calculated: " + m.standardErrors()[i] + "\n expected: " + errorsExpected[i] + "\n tolerance: " + tol); } if (Math.Abs(m.coefficients()[i] - coeffExpected[i]) > tol) { Assert.Fail("Failed to reproduce linear regression coef." + "\n calculated: " + m.coefficients()[i] + "\n expected: " + coeffExpected[i] + "\n tolerance: " + tol); } } }
public override void fetchResults(IPricingEngineResults r) { base.fetchResults(r); LoanPricingEngineResults results = r as LoanPricingEngineResults; if (results == null) throw new ArgumentException("wrong result type"); if (results.legNPV.Count != 0) { if (results.legNPV.Count != legNPV_.Count) { throw new ArgumentException("wrong number of leg NPV returned"); } legNPV_ = results.legNPV; } else { legNPV_ = new InitializedList<double?>(legNPV_.Count); } }
public MersenneTwisterUniformRng(List<ulong> seeds) { mt = new InitializedList<ulong>(N); seedInitialization(19650218UL); int i = 1, j = 0, k = (N > seeds.Count ? N : seeds.Count); for (; k!=0; k--) { mt[i] = (mt[i] ^ ((mt[i - 1] ^ (mt[i - 1] >> 30)) * 1664525UL)) + seeds[j] + (ulong)j; /* non linear */ mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */ i++; j++; if (i>=N) { mt[0] = mt[N-1]; i=1; } if (j>=seeds.Count) j=0; } for (k=N-1; k!=0; k--) { mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1566083941UL)) - (ulong)i; /* non linear */ mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */ i++; if (i>=N) { mt[0] = mt[N-1]; i=1; } } mt[0] = 0x80000000UL; /*MSB is 1; assuring non-zero initial array*/ }
// Instrument interface public override void calculate() { if (discountCurve_.empty()) throw new ArgumentException("no discounting term structure set"); results_.value = results_.cash = 0; results_.errorEstimate = null; results_.legNPV = new InitializedList<double?>(arguments_.legs.Count); results_.legBPS = new InitializedList<double?>(arguments_.legs.Count); List<double?> startDiscounts = new InitializedList<double?>(arguments_.legs.Count); for (int i=0; i<arguments_.legs.Count; ++i) { results_.legNPV[i] = arguments_.payer[i] * CashFlows.npv(arguments_.legs[i], discountCurve_); results_.legBPS[i] = arguments_.payer[i] * CashFlows.bps(arguments_.legs[i], discountCurve_); results_.value += results_.legNPV[i]; results_.cash += arguments_.payer[i] * CashFlows.cash(arguments_.legs[i]); try { Date d = CashFlows.startDate(arguments_.legs[i]); startDiscounts[i] = discountCurve_.link.discount(d); } catch { startDiscounts[i] = null; } } results_.additionalResults.Add("startDiscounts", startDiscounts); }
public void setMarketData() { tenors = new SwaptionTenors(); //tenors.options.resize(6); tenors.options = new InitializedList<Period>(6); tenors.options[0] = new Period(1, TimeUnit.Months); tenors.options[1] = new Period(6, TimeUnit.Months); tenors.options[2] = new Period(1, TimeUnit.Years); tenors.options[3] = new Period(5, TimeUnit.Years); tenors.options[4] = new Period(10, TimeUnit.Years); tenors.options[5] = new Period(30, TimeUnit.Years); //tenors.swaps.resize(4); tenors.swaps = new InitializedList<Period>(4); tenors.swaps[0] = new Period(1, TimeUnit.Years); tenors.swaps[1] = new Period(5, TimeUnit.Years); tenors.swaps[2] = new Period(10, TimeUnit.Years); tenors.swaps[3] = new Period(30, TimeUnit.Years); vols = new Matrix(tenors.options.Count, tenors.swaps.Count); vols[0, 0] = 0.1300; vols[0, 1] = 0.1560; vols[0, 2] = 0.1390; vols[0, 3] = 0.1220; vols[1, 0] = 0.1440; vols[1, 1] = 0.1580; vols[1, 2] = 0.1460; vols[1, 3] = 0.1260; vols[2, 0] = 0.1600; vols[2, 1] = 0.1590; vols[2, 2] = 0.1470; vols[2, 3] = 0.1290; vols[3, 0] = 0.1640; vols[3, 1] = 0.1470; vols[3, 2] = 0.1370; vols[3, 3] = 0.1220; vols[4, 0] = 0.1400; vols[4, 1] = 0.1300; vols[4, 2] = 0.1250; vols[4, 3] = 0.1100; vols[5, 0] = 0.1130; vols[5, 1] = 0.1090; vols[5, 2] = 0.1070; vols[5, 3] = 0.0930; volsHandle = new InitializedList<List<Handle<Quote>>>(tenors.options.Count); for (int i = 0; i < tenors.options.Count; i++) { volsHandle[i] = new InitializedList<Handle<Quote>>(tenors.swaps.Count); for (int j = 0; j < tenors.swaps.Count; j++) // every handle must be reassigned, as the ones created by // default are all linked together. volsHandle[i][j] = new Handle<Quote>(new SimpleQuote(vols[i, j])); } }
public override void update() { Vector tmp = new Vector(size_); List<double> dx = new InitializedList<double>(size_ - 1), S = new InitializedList<double>(size_ - 1); for (int i = 0; i < size_ - 1; ++i) { dx[i] = xBegin_[i+1] - xBegin_[i]; S[i] = (yBegin_[i+1] - yBegin_[i])/dx[i]; } // first derivative approximation if (da_==CubicInterpolation.DerivativeApprox.Spline) { TridiagonalOperator L = new TridiagonalOperator(size_); for (int i = 1; i < size_ - 1; ++i) { L.setMidRow(i, dx[i], 2.0*(dx[i]+dx[i-1]), dx[i-1]); tmp[i] = 3.0*(dx[i]*S[i-1] + dx[i-1]*S[i]); } // left boundary condition switch (leftType_) { case CubicInterpolation.BoundaryCondition.NotAKnot: // ignoring end condition value L.setFirstRow(dx[1]*(dx[1]+dx[0]), (dx[0]+dx[1])*(dx[0]+dx[1])); tmp[0] = S[0]*dx[1]*(2.0*dx[1]+3.0*dx[0]) + S[1]*dx[0]*dx[0]; break; case CubicInterpolation.BoundaryCondition.FirstDerivative: L.setFirstRow(1.0, 0.0); tmp[0] = leftValue_; break; case CubicInterpolation.BoundaryCondition.SecondDerivative: L.setFirstRow(2.0, 1.0); tmp[0] = 3.0*S[0] - leftValue_*dx[0]/2.0; break; case CubicInterpolation.BoundaryCondition.Periodic: case CubicInterpolation.BoundaryCondition.Lagrange: // ignoring end condition value throw new NotImplementedException("this end condition is not implemented yet"); default: throw new ArgumentException("unknown end condition"); } // right boundary condition switch (rightType_) { case CubicInterpolation.BoundaryCondition.NotAKnot: // ignoring end condition value L.setLastRow(-(dx[size_ - 2] + dx[size_ - 3]) * (dx[size_ - 2] + dx[size_ - 3]), -dx[size_ - 3] * (dx[size_ - 3] + dx[size_ - 2])); tmp[size_ - 1] = -S[size_ - 3] * dx[size_ - 2] * dx[size_ - 2] - S[size_ - 2] * dx[size_ - 3] * (3.0 * dx[size_ - 2] + 2.0 * dx[size_ - 3]); break; case CubicInterpolation.BoundaryCondition.FirstDerivative: L.setLastRow(0.0, 1.0); tmp[size_ - 1] = rightValue_; break; case CubicInterpolation.BoundaryCondition.SecondDerivative: L.setLastRow(1.0, 2.0); tmp[size_ - 1] = 3.0 * S[size_ - 2] + rightValue_ * dx[size_ - 2] / 2.0; break; case CubicInterpolation.BoundaryCondition.Periodic: case CubicInterpolation.BoundaryCondition.Lagrange: // ignoring end condition value throw new NotImplementedException("this end condition is not implemented yet"); default: throw new ArgumentException("unknown end condition"); } // solve the system tmp = L.solveFor(tmp); } else { // local schemes if (size_ == 2) tmp[0] = tmp[1] = S[0]; else { switch (da_) { case CubicInterpolation.DerivativeApprox.FourthOrder: throw new NotImplementedException("FourthOrder not implemented yet"); break; case CubicInterpolation.DerivativeApprox.Parabolic: // intermediate points for (int i = 1; i < size_ - 1; ++i) { tmp[i] = (dx[i - 1] * S[i] + dx[i] * S[i - 1]) / (dx[i] + dx[i - 1]); } // end points tmp[0] = ((2.0 * dx[0] + dx[1]) * S[0] - dx[0] * S[1]) / (dx[0] + dx[1]); tmp[size_ - 1] = ((2.0 * dx[size_ - 2] + dx[size_ - 3]) * S[size_ - 2] - dx[size_ - 2] * S[size_ - 3]) / (dx[size_ - 2] + dx[size_ - 3]); break; break; case CubicInterpolation.DerivativeApprox.FritschButland: // intermediate points for (int i=1; i<size_-1; ++i) { double Smin = Math.Min(S[i-1], S[i]); double Smax = Math.Max(S[i-1], S[i]); tmp[i] = 3.0*Smin*Smax/(Smax+2.0*Smin); } // end points tmp[0] = ((2.0*dx[ 0]+dx[ 1])*S[ 0] - dx[ 0]*S[ 1]) / (dx[ 0]+dx[ 1]); tmp[size_-1] = ((2.0*dx[size_-2]+dx[size_-3])*S[size_-2] - dx[size_-2]*S[size_-3]) / (dx[size_-2]+dx[size_-3]); break; case CubicInterpolation.DerivativeApprox.Akima: throw new NotImplementedException("Akima not implemented yet"); // end points tmp[0] = ((2.0 * dx[0] + dx[1]) * S[0] - dx[0] * S[1]) / (dx[0] + dx[1]); tmp[size_ - 1] = ((2.0 * dx[size_ - 2] + dx[size_ - 3]) * S[size_ - 2] - dx[size_ - 2] * S[size_ - 3]) / (dx[size_ - 2] + dx[size_ - 3]); break; case CubicInterpolation.DerivativeApprox.Kruger: // intermediate points for (int i = 1; i < size_ - 1; ++i) { if (S[i-1]*S[i]<0.0) // slope changes sign at point tmp[i] = 0.0; else // slope will be between the slopes of the adjacent // straight lines and should approach zero if the // slope of either line approaches zero tmp[i] = 2.0/(1.0/S[i-1]+1.0/S[i]); } // end points tmp[0] = (3.0*S[0]-tmp[1])/2.0; tmp[size_ - 1] = (3.0 * S[size_ - 2] - tmp[size_ - 2]) / 2.0; break; default: throw new ArgumentException("unknown scheme"); } } } monotonicityAdjustments_.Erase(); // Hyman monotonicity constrained filter if (monotonic_) { double correction; double pm, pu, pd, M; for (int i = 0; i < size_; ++i) { if (i==0) { if (tmp[i]*S[0]>0.0) { correction = tmp[i]/Math.Abs(tmp[i]) * Math.Min(Math.Abs(tmp[i]), Math.Abs(3.0*S[0])); } else { correction = 0.0; } if (correction!=tmp[i]) { tmp[i] = correction; monotonicityAdjustments_[i] = true; } } else if (i == size_ - 1) { if (tmp[i] * S[size_ - 2] > 0.0) { correction = tmp[i]/Math.Abs(tmp[i]) * Math.Min(Math.Abs(tmp[i]), Math.Abs(3.0 * S[size_ - 2])); } else { correction = 0.0; } if (correction!=tmp[i]) { tmp[i] = correction; monotonicityAdjustments_[i] = true; } } else { pm=(S[i-1]*dx[i]+S[i]*dx[i-1])/ (dx[i-1]+dx[i]); M = 3.0 * Math.Min(Math.Min(Math.Abs(S[i-1]), Math.Abs(S[i])), Math.Abs(pm)); if (i>1) { if ((S[i-1]-S[i-2])*(S[i]-S[i-1])>0.0) { pd=(S[i-1]*(2.0*dx[i-1]+dx[i-2]) -S[i-2]*dx[i-1])/ (dx[i-2]+dx[i-1]); if (pm*pd>0.0 && pm*(S[i-1]-S[i-2])>0.0) { M = Math.Max(M, 1.5*Math.Min( Math.Abs(pm),Math.Abs(pd))); } } } if (i < size_ - 2) { if ((S[i]-S[i-1])*(S[i+1]-S[i])>0.0) { pu=(S[i]*(2.0*dx[i]+dx[i+1])-S[i+1]*dx[i])/ (dx[i]+dx[i+1]); if (pm*pu>0.0 && -pm*(S[i]-S[i-1])>0.0) { M = Math.Max(M, 1.5*Math.Min( Math.Abs(pm),Math.Abs(pu))); } } } if (tmp[i]*pm>0.0) { correction = tmp[i]/Math.Abs(tmp[i]) * Math.Min(Math.Abs(tmp[i]), M); } else { correction = 0.0; } if (correction!=tmp[i]) { tmp[i] = correction; monotonicityAdjustments_[i] = true; } } } } // cubic coefficients for (int i = 0; i < size_ - 1; ++i) { a_[i] = tmp[i]; b_[i] = (3.0*S[i] - tmp[i+1] - 2.0*tmp[i])/dx[i]; c_[i] = (tmp[i+1] + tmp[i] - 2.0*S[i])/(dx[i]*dx[i]); } primitiveConst_[0] = 0.0; for (int i = 1; i < size_ - 1; ++i) { primitiveConst_[i] = primitiveConst_[i-1] + dx[i-1] * (yBegin_[i-1] + dx[i-1] * (a_[i-1]/2.0 + dx[i-1] * (b_[i-1]/3.0 + dx[i-1] * c_[i-1]/4.0))); } }
public void testFdmLinearOpLayout() { int[] dims = new int[] { 5, 7, 8 }; List <int> dim = new List <int>(dims); FdmLinearOpLayout layout = new FdmLinearOpLayout(dim); int calculatedDim = layout.dim().Count; int expectedDim = dim.Count; if (calculatedDim != expectedDim) { QAssert.Fail("index.dimensions() should be " + expectedDim + ", but is " + calculatedDim); } int calculatedSize = layout.size(); int expectedSize = dim.accumulate(0, 3, 1, (x, y) => (x * y)); if (calculatedSize != expectedSize) { QAssert.Fail("index.size() should be " + expectedSize + ", but is " + calculatedSize); } for (int k = 0; k < dim[0]; ++k) { for (int l = 0; l < dim[1]; ++l) { for (int m = 0; m < dim[2]; ++m) { List <int> tmp = new InitializedList <int>(3); tmp[0] = k; tmp[1] = l; tmp[2] = m; int calculatedIndex = layout.index(tmp); int expectedIndex = k + l * dim[0] + m * dim[0] * dim[1]; if (expectedIndex != layout.index(tmp)) { QAssert.Fail("index.size() should be " + expectedIndex + ", but is " + calculatedIndex); } } } } FdmLinearOpIterator iter = layout.begin(); for (int m = 0; m < dim[2]; ++m) { for (int l = 0; l < dim[1]; ++l) { for (int k = 0; k < dim[0]; ++k, ++iter) { for (int n = 1; n < 4; ++n) { int nn = layout.neighbourhood(iter, 1, n); int calculatedIndex = k + m * dim[0] * dim[1] + ((l < dim[1] - n)? l + n : dim[1] - 1 - (l + n - (dim[1] - 1))) * dim[0]; if (nn != calculatedIndex) { QAssert.Fail("next neighbourhood index is " + nn + " but should be " + calculatedIndex); } } for (int n = 1; n < 7; ++n) { int nn = layout.neighbourhood(iter, 2, -n); int calculatedIndex = k + l * dim[0] + ((m < n) ? n - m : m - n) * dim[0] * dim[1]; if (nn != calculatedIndex) { QAssert.Fail("next neighbourhood index is " + nn + " but should be " + calculatedIndex); } } } } } }
protected List<double> sinkingNotionals(Period maturityTenor, Frequency sinkingFrequency, double couponRate, double initialNotional) { Period freqPeriod = new Period(sinkingFrequency); int nPeriods = 0; Utils.QL_REQUIRE(isSubPeriod(freqPeriod, maturityTenor, out nPeriods),() => "Bond frequency is incompatible with the maturity tenor"); List<double> notionals = new InitializedList<double>(nPeriods+1); notionals[0] = initialNotional; double coupon = couponRate / (double)sinkingFrequency; double compoundedInterest = 1.0; double totalValue = Math.Pow(1.0+coupon, nPeriods); for(int i = 0; i < (int)nPeriods-1; ++i) { compoundedInterest *= (1.0 + coupon); double currentNotional = 0.0; if(coupon < 1.0e-12) { currentNotional = initialNotional*(1.0 - (i+1.0)/nPeriods); } else { currentNotional = initialNotional*(compoundedInterest - (compoundedInterest-1.0)/(1.0 - 1.0/totalValue)); } notionals[i+1] = currentNotional; } notionals[notionals.Count-1] = 0.0; return notionals; }
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 void testCachedFloating() { // "Testing floating-rate bond prices against cached values..."); CommonVars vars = new CommonVars(); Date today = new Date(22, Month.November, 2004); Settings.setEvaluationDate(today); int settlementDays = 1; var riskFreeRate = new Handle <YieldTermStructure>(Utilities.flatRate(today, 0.025, new Actual360())); var discountCurve = new Handle <YieldTermStructure>(Utilities.flatRate(today, 0.03, new Actual360())); IborIndex index = new USDLibor(new Period(6, TimeUnit.Months), riskFreeRate); int fixingDays = 1; double tolerance = 1.0e-6; IborCouponPricer pricer = new BlackIborCouponPricer(new Handle <OptionletVolatilityStructure>()); // plain Schedule sch = new Schedule(new Date(30, Month.November, 2004), new Date(30, Month.November, 2008), new Period(Frequency.Semiannual), new UnitedStates(UnitedStates.Market.GovernmentBond), BusinessDayConvention.ModifiedFollowing, BusinessDayConvention.ModifiedFollowing, DateGeneration.Rule.Backward, false); FloatingRateBond bond1 = new FloatingRateBond(settlementDays, vars.faceAmount, sch, index, new ActualActual(ActualActual.Convention.ISMA), BusinessDayConvention.ModifiedFollowing, fixingDays, new List <double>(), new List <double>(), new List <double>(), new List <double>(), false, 100.0, new Date(30, Month.November, 2004)); IPricingEngine bondEngine = new DiscountingBondEngine(riskFreeRate); bond1.setPricingEngine(bondEngine); Utils.setCouponPricer(bond1.cashflows(), pricer); #if QL_USE_INDEXED_COUPON double cachedPrice1 = 99.874645; #else double cachedPrice1 = 99.874646; #endif double price = bond1.cleanPrice(); if (Math.Abs(price - cachedPrice1) > tolerance) { Assert.Fail("failed to reproduce cached price:\n" + " calculated: " + price + "\n" + " expected: " + cachedPrice1 + "\n" + " error: " + (price - cachedPrice1)); } // different risk-free and discount curve FloatingRateBond bond2 = new FloatingRateBond(settlementDays, vars.faceAmount, sch, index, new ActualActual(ActualActual.Convention.ISMA), BusinessDayConvention.ModifiedFollowing, fixingDays, new List <double>(), new List <double>(), new List <double>(), new List <double>(), false, 100.0, new Date(30, Month.November, 2004)); IPricingEngine bondEngine2 = new DiscountingBondEngine(discountCurve); bond2.setPricingEngine(bondEngine2); Utils.setCouponPricer(bond2.cashflows(), pricer); #if QL_USE_INDEXED_COUPON double cachedPrice2 = 97.955904; #else double cachedPrice2 = 97.955904; #endif price = bond2.cleanPrice(); if (Math.Abs(price - cachedPrice2) > tolerance) { Assert.Fail("failed to reproduce cached price:\n" + " calculated: " + price + "\n" + " expected: " + cachedPrice2 + "\n" + " error: " + (price - cachedPrice2)); } // varying spread InitializedList <double> spreads = new InitializedList <double>(4); spreads[0] = 0.001; spreads[1] = 0.0012; spreads[2] = 0.0014; spreads[3] = 0.0016; FloatingRateBond bond3 = new FloatingRateBond(settlementDays, vars.faceAmount, sch, index, new ActualActual(ActualActual.Convention.ISMA), BusinessDayConvention.ModifiedFollowing, fixingDays, new List <double>(), spreads, new List <double>(), new List <double>(), false, 100.0, new Date(30, Month.November, 2004)); bond3.setPricingEngine(bondEngine2); Utils.setCouponPricer(bond3.cashflows(), pricer); #if QL_USE_INDEXED_COUPON double cachedPrice3 = 98.495458; #else double cachedPrice3 = 98.495459; #endif price = bond3.cleanPrice(); if (Math.Abs(price - cachedPrice3) > tolerance) { Assert.Fail("failed to reproduce cached price:\n" + " calculated: " + price + "\n" + " expected: " + cachedPrice3 + "\n" + " error: " + (price - cachedPrice3)); } }
public void testStrikeDependency() { //("Testing swaption dependency on strike......"); CommonVars vars = new CommonVars(); double[] strikes = new double[] { 0.03, 0.04, 0.05, 0.06, 0.07 }; for (int i = 0; i < exercises.Length; i++) { for (int j = 0; j < lengths.Length; j++) { for (int k=0; k < type.Length ; k++) { Date exerciseDate = vars.calendar.advance(vars.today, exercises[i]); Date startDate = vars.calendar.advance(exerciseDate, vars.settlementDays, TimeUnit.Days); // store the results for different rates... List<double> values = new InitializedList<double>(strikes.Length); List<double> values_cash = new InitializedList<double>(strikes.Length); double vol = 0.20; for (int l=0; l< strikes.Length ; l++) { VanillaSwap swap = new MakeVanillaSwap(lengths[j], vars.index, strikes[l]) .withEffectiveDate(startDate) .withFloatingLegSpread(0.0) .withType(type[k]); Swaption swaption = vars.makeSwaption(swap,exerciseDate,vol); // FLOATING_POINT_EXCEPTION values[l]=swaption.NPV(); Swaption swaption_cash = vars.makeSwaption( swap,exerciseDate,vol, Settlement.Type.Cash); values_cash[l]=swaption_cash.NPV(); } // and check that they go the right way if (type[k]==VanillaSwap.Type.Payer) { for (int z = 0; z < values.Count - 1; z++) { if( values[z]<values[z+1]){ Assert.Fail("NPV of Payer swaption with delivery settlement"+ "is increasing with the strike:" + "\noption tenor: " + exercises[i] + "\noption date: " + exerciseDate + "\nvolatility: " + vol + "\nswap tenor: " + lengths[j] + "\nvalue: " + values[z ] +" at strike: " + strikes[z ] + "\nvalue: " + values[z+1] + " at strike: " + strikes[z+1]); } } for (int z = 0; z < values_cash.Count - 1; z++) { if (values_cash[z] < values_cash[z + 1]) { Assert.Fail("NPV of Payer swaption with cash settlement" + "is increasing with the strike:" + "\noption tenor: " + exercises[i] + "\noption date: " + exerciseDate + "\nvolatility: " + vol + "\nswap tenor: " + lengths[j] + "\nvalue: " + values_cash[z] + " at strike: " + strikes[z] + "\nvalue: " + values_cash[z + 1] + " at strike: " + strikes[z + 1]); } } } else { for (int z = 0; z < values.Count - 1; z++){ if (values[z] > values[z+1]){ Assert.Fail("NPV of Receiver swaption with delivery settlement" + "is increasing with the strike:" + "\noption tenor: " + exercises[i] + "\noption date: " + exerciseDate + "\nvolatility: " + vol + "\nswap tenor: " + lengths[j] + "\nvalue: " + values[z] + " at strike: " + strikes[z] + "\nvalue: " + values[z + 1] + " at strike: " + strikes[z + 1]); } } for (int z = 0; z < values_cash.Count - 1; z++) { if (values[z] > values[z+1]) { Assert.Fail("NPV of Receiver swaption with cash settlement" + "is increasing with the strike:" + "\noption tenor: " + exercises[i] + "\noption date: " + exerciseDate + "\nvolatility: " + vol + "\nswap tenor: " + lengths[j] + "\nvalue: " + values_cash[z] + " at strike: " + strikes[z] + "\nvalue: " + values_cash[z + 1] + " at strike: " + strikes[z + 1]); } } } } } } }
public void testCachedFixed() { // "Testing fixed-coupon bond prices against cached values..."); CommonVars vars = new CommonVars(); Date today = new Date(22, Month.November, 2004); Settings.setEvaluationDate(today); int settlementDays = 1; var discountCurve = new Handle<YieldTermStructure>(Utilities.flatRate(today, 0.03, new Actual360())); double tolerance = 1.0e-6; // plain Schedule sch = new Schedule(new Date(30, Month.November, 2004), new Date(30, Month.November, 2008), new Period(Frequency.Semiannual), new UnitedStates(UnitedStates.Market.GovernmentBond), BusinessDayConvention.Unadjusted, BusinessDayConvention.Unadjusted, DateGeneration.Rule.Backward, false); FixedRateBond bond1 = new FixedRateBond(settlementDays, vars.faceAmount, sch, new List<double>() { 0.02875 }, new ActualActual(ActualActual.Convention.ISMA), BusinessDayConvention.ModifiedFollowing, 100.0, new Date(30, Month.November, 2004)); IPricingEngine bondEngine = new DiscountingBondEngine(discountCurve); bond1.setPricingEngine(bondEngine); double cachedPrice1 = 99.298100; double price = bond1.cleanPrice(); if (Math.Abs(price - cachedPrice1) > tolerance) { Console.WriteLine("failed to reproduce cached price:\n" + " calculated: " + price + "\n" + " expected: " + cachedPrice1 + "\n" + " error: " + (price - cachedPrice1)); } // varying coupons InitializedList<double> couponRates = new InitializedList<double>(4); couponRates[0] = 0.02875; couponRates[1] = 0.03; couponRates[2] = 0.03125; couponRates[3] = 0.0325; FixedRateBond bond2 = new FixedRateBond(settlementDays, vars.faceAmount, sch, couponRates, new ActualActual(ActualActual.Convention.ISMA), BusinessDayConvention.ModifiedFollowing, 100.0, new Date(30, Month.November, 2004)); bond2.setPricingEngine(bondEngine); double cachedPrice2 = 100.334149; price = bond2.cleanPrice(); if (Math.Abs(price - cachedPrice2) > tolerance) { Console.WriteLine("failed to reproduce cached price:\n" + " calculated: " + price + "\n" + " expected: " + cachedPrice2 + "\n" + " error: " + (price - cachedPrice2)); } // stub date Schedule sch3 = new Schedule(new Date(30, Month.November, 2004), new Date(30, Month.March, 2009), new Period(Frequency.Semiannual), new UnitedStates(UnitedStates.Market.GovernmentBond), BusinessDayConvention.Unadjusted, BusinessDayConvention.Unadjusted, DateGeneration.Rule.Backward, false, null, new Date(30, Month.November, 2008)); FixedRateBond bond3 = new FixedRateBond(settlementDays, vars.faceAmount, sch3, couponRates, new ActualActual(ActualActual.Convention.ISMA), BusinessDayConvention.ModifiedFollowing, 100.0, new Date(30, Month.November, 2004)); bond3.setPricingEngine(bondEngine); double cachedPrice3 = 100.382794; price = bond3.cleanPrice(); if (Math.Abs(price - cachedPrice3) > tolerance) { Assert.Fail("failed to reproduce cached price:\n" + " calculated: " + price + "\n" + " expected: " + cachedPrice3 + "\n" + " error: " + (price - cachedPrice3)); } }
public void testObservability() { // Testing volatility cube observability CommonVars vars = new CommonVars(); List <List <Handle <Quote> > > parametersGuess = new InitializedList <List <Handle <Quote> > >(vars.cube.tenors.options.Count * vars.cube.tenors.swaps.Count); for (int i = 0; i < vars.cube.tenors.options.Count * vars.cube.tenors.swaps.Count; i++) { parametersGuess[i] = new InitializedList <Handle <Quote> >(4); parametersGuess[i][0] = new Handle <Quote>(new SimpleQuote(0.2)); parametersGuess[i][1] = new Handle <Quote>(new SimpleQuote(0.5)); parametersGuess[i][2] = new Handle <Quote>(new SimpleQuote(0.4)); parametersGuess[i][3] = new Handle <Quote>(new SimpleQuote(0.0)); } List <bool> isParameterFixed = new InitializedList <bool>(4, false); SwaptionVolCube1x volCube1_0, volCube1_1; // VolCube created before change of reference date volCube1_0 = new SwaptionVolCube1x(vars.atmVolMatrix, vars.cube.tenors.options, vars.cube.tenors.swaps, vars.cube.strikeSpreads, vars.cube.volSpreadsHandle, vars.swapIndexBase, vars.shortSwapIndexBase, vars.vegaWeighedSmileFit, parametersGuess, isParameterFixed, true); Date referenceDate = Settings.evaluationDate(); Settings.setEvaluationDate(vars.conventions.calendar.advance(referenceDate, new Period(1, TimeUnit.Days), vars.conventions.optionBdc)); // VolCube created after change of reference date volCube1_1 = new SwaptionVolCube1x(vars.atmVolMatrix, vars.cube.tenors.options, vars.cube.tenors.swaps, vars.cube.strikeSpreads, vars.cube.volSpreadsHandle, vars.swapIndexBase, vars.shortSwapIndexBase, vars.vegaWeighedSmileFit, parametersGuess, isParameterFixed, true); double dummyStrike = 0.03; for (int i = 0; i < vars.cube.tenors.options.Count; i++) { for (int j = 0; j < vars.cube.tenors.swaps.Count; j++) { for (int k = 0; k < vars.cube.strikeSpreads.Count; k++) { double v0 = volCube1_0.volatility(vars.cube.tenors.options[i], vars.cube.tenors.swaps[j], dummyStrike + vars.cube.strikeSpreads[k], false); double v1 = volCube1_1.volatility(vars.cube.tenors.options[i], vars.cube.tenors.swaps[j], dummyStrike + vars.cube.strikeSpreads[k], false); if (Math.Abs(v0 - v1) > 1e-14) { QAssert.Fail(" option tenor = " + vars.cube.tenors.options[i] + " swap tenor = " + vars.cube.tenors.swaps[j] + " strike = " + (dummyStrike + vars.cube.strikeSpreads[k]) + " v0 = " + (v0) + " v1 = " + (v1) + " error = " + Math.Abs(v1 - v0)); } } } } Settings.setEvaluationDate(referenceDate); SwaptionVolCube2 volCube2_0, volCube2_1; // VolCube created before change of reference date volCube2_0 = new SwaptionVolCube2(vars.atmVolMatrix, vars.cube.tenors.options, vars.cube.tenors.swaps, vars.cube.strikeSpreads, vars.cube.volSpreadsHandle, vars.swapIndexBase, vars.shortSwapIndexBase, vars.vegaWeighedSmileFit); Settings.setEvaluationDate(vars.conventions.calendar.advance(referenceDate, new Period(1, TimeUnit.Days), vars.conventions.optionBdc)); // VolCube created after change of reference date volCube2_1 = new SwaptionVolCube2(vars.atmVolMatrix, vars.cube.tenors.options, vars.cube.tenors.swaps, vars.cube.strikeSpreads, vars.cube.volSpreadsHandle, vars.swapIndexBase, vars.shortSwapIndexBase, vars.vegaWeighedSmileFit); for (int i = 0; i < vars.cube.tenors.options.Count; i++) { for (int j = 0; j < vars.cube.tenors.swaps.Count; j++) { for (int k = 0; k < vars.cube.strikeSpreads.Count; k++) { double v0 = volCube2_0.volatility(vars.cube.tenors.options[i], vars.cube.tenors.swaps[j], dummyStrike + vars.cube.strikeSpreads[k], false); double v1 = volCube2_1.volatility(vars.cube.tenors.options[i], vars.cube.tenors.swaps[j], dummyStrike + vars.cube.strikeSpreads[k], false); if (Math.Abs(v0 - v1) > 1e-14) { QAssert.Fail(" option tenor = " + vars.cube.tenors.options[i] + " swap tenor = " + vars.cube.tenors.swaps[j] + " strike = " + (dummyStrike + vars.cube.strikeSpreads[k]) + " v0 = " + (v0) + " v1 = " + (v1) + " error = " + Math.Abs(v1 - v0)); } } } } Settings.setEvaluationDate(referenceDate); }
static void Main(string[] args) { DateTime timer = DateTime.Now; //////////////// DATES ////////////////////////////////////////////// Calendar calendar = new TARGET(); Date todaysDate = new Date(15, Month.January, 2017); Date settlementDate = new Date(todaysDate); Settings.setEvaluationDate(todaysDate); DayCounter dayCounter = new Actual365Fixed(); //////////////// MARKET ////////////////////////////////////////////// // Spot double underlying = 1.0; Handle <Quote> underlyingH = new Handle <Quote>(new SimpleQuote(underlying)); // Curves double riskFreeRate = 0.01; double dividendYield = 0.035; double cstVol = 0.2; double hazardRate = 0.02; Handle <YieldTermStructure> flatTermStructure = new Handle <YieldTermStructure>(new FlatForward(settlementDate, riskFreeRate, dayCounter)); Handle <YieldTermStructure> flatDividendTS = new Handle <YieldTermStructure>(new FlatForward(settlementDate, dividendYield, dayCounter)); Handle <BlackVolTermStructure> mySurfaceH = new Handle <BlackVolTermStructure>(new BlackConstantVol(settlementDate, calendar, cstVol, dayCounter)); Handle <DefaultProbabilityTermStructure> defaultTSH = new Handle <DefaultProbabilityTermStructure>(new FlatHazardRate(settlementDate, hazardRate, dayCounter)); // Process GeneralizedBlackScholesProcessTolerance bsmProcess = new GeneralizedBlackScholesProcessTolerance(underlyingH, flatDividendTS, flatTermStructure, mySurfaceH); //////////////// INSTRUMENT ////////////////////////////////////////////// List <Date> fixings = new InitializedList <Date>(); for (int i = 1; i <= 8; i++) { fixings.Add(settlementDate + new Period(i * 3, TimeUnit.Months)); } double couponBond = 0.0525; double couponBinary = 0.077; double barrierlvl = 0.7; double strike = 1.0; double recovery = 0.4; double absoluteTolerance = 0.0001; GenericScriptRepack repack = new GenericScriptRepack(fixings, couponBond, couponBinary, barrierlvl, strike, recovery); IPricingEngine mcengine = new MakeMCGenericScriptInstrument <PseudoRandom>(bsmProcess) .withAbsoluteTolerance(absoluteTolerance) .withStepsPerYear(52) .withSeed(50) .withCredit(defaultTSH) .value(); repack.setPricingEngine(mcengine); Console.WriteLine("Repack pricing = {0:0.0000}", repack.NPV()); repack.inspout(5, true); //////////////// END TEST ////////////////////////////////////////////// Console.WriteLine(); Console.WriteLine(" \nRun completed in {0}", DateTime.Now - timer); Console.WriteLine(); Console.Write("Press any key to continue ..."); Console.ReadKey(); }
public void testRegression() { //("Testing linear least-squares regression..."); //SavedSettings backup; const int nr = 100000; var rng = new InverseCumulativeRng <MersenneTwisterUniformRng, InverseCumulativeNormal>( new MersenneTwisterUniformRng(1234u)); List <Func <double, double> > v = new List <Func <double, double> >(); v.Add(x => 1.0); v.Add(x => x); v.Add(x => x * x); v.Add(Math.Sin); List <Func <double, double> > w = new List <Func <double, double> >(v); w.Add(x => x * x); for (int k = 0; k < 3; ++k) { int i; double[] a = { rng.next().value, rng.next().value, rng.next().value, rng.next().value }; List <double> x = new InitializedList <double>(nr), y = new InitializedList <double>(nr); for (i = 0; i < nr; ++i) { x[i] = rng.next().value; // regression in y = a_1 + a_2*x + a_3*x^2 + a_4*sin(x) + eps y[i] = a[0] * v[0](x[i]) + a[1] * v[1](x[i]) + a[2] * v[2](x[i]) + a[3] * v[3](x[i]) + rng.next().value; } LinearLeastSquaresRegression m = new LinearLeastSquaresRegression(x, y, v); for (i = 0; i < v.Count; ++i) { if (m.standardErrors()[i] > tolerance) { Assert.Fail("Failed to reproduce linear regression coef." + "\n error: " + m.standardErrors()[i] + "\n tolerance: " + tolerance); } if (Math.Abs(m.coefficients()[i] - a[i]) > 3 * m.error()[i]) { Assert.Fail("Failed to reproduce linear regression coef." + "\n calculated: " + m.coefficients()[i] + "\n error: " + m.standardErrors()[i] + "\n expected: " + a[i]); } } m = new LinearLeastSquaresRegression(x, y, w); double[] ma = { m.coefficients()[0], m.coefficients()[1], m.coefficients()[2] + m.coefficients()[4], m.coefficients()[3] }; double[] err = { m.standardErrors()[0], m.standardErrors()[1], Math.Sqrt(m.standardErrors()[2] * m.standardErrors()[2] + m.standardErrors()[4] * m.standardErrors()[4]), m.standardErrors()[3] }; for (i = 0; i < v.Count; ++i) { if (Math.Abs(ma[i] - a[i]) > 3 * err[i]) { Assert.Fail("Failed to reproduce linear regression coef." + "\n calculated: " + ma[i] + "\n error: " + err[i] + "\n expected: " + a[i]); } } } }
public void testSpreadedCube() { // Testing spreaded swaption volatility cube CommonVars vars = new CommonVars(); List <List <Handle <Quote> > > parametersGuess = new InitializedList <List <Handle <Quote> > >(vars.cube.tenors.options.Count * vars.cube.tenors.swaps.Count); for (int i = 0; i < vars.cube.tenors.options.Count * vars.cube.tenors.swaps.Count; i++) { parametersGuess[i] = new InitializedList <Handle <Quote> >(4); parametersGuess[i][0] = new Handle <Quote>(new SimpleQuote(0.2)); parametersGuess[i][1] = new Handle <Quote>(new SimpleQuote(0.5)); parametersGuess[i][2] = new Handle <Quote>(new SimpleQuote(0.4)); parametersGuess[i][3] = new Handle <Quote>(new SimpleQuote(0.0)); } List <bool> isParameterFixed = new InitializedList <bool>(4, false); Handle <SwaptionVolatilityStructure> volCube = new Handle <SwaptionVolatilityStructure>( new SwaptionVolCube1x(vars.atmVolMatrix, vars.cube.tenors.options, vars.cube.tenors.swaps, vars.cube.strikeSpreads, vars.cube.volSpreadsHandle, vars.swapIndexBase, vars.shortSwapIndexBase, vars.vegaWeighedSmileFit, parametersGuess, isParameterFixed, true)); SimpleQuote spread = new SimpleQuote(0.0001); Handle <Quote> spreadHandle = new Handle <Quote>(spread); SwaptionVolatilityStructure spreadedVolCube = new SpreadedSwaptionVolatility(volCube, spreadHandle); List <double> strikes = new List <double>(); for (int k = 1; k < 100; k++) { strikes.Add(k * .01); } for (int i = 0; i < vars.cube.tenors.options.Count; i++) { for (int j = 0; j < vars.cube.tenors.swaps.Count; j++) { SmileSection smileSectionByCube = volCube.link.smileSection(vars.cube.tenors.options[i], vars.cube.tenors.swaps[j]); SmileSection smileSectionBySpreadedCube = spreadedVolCube.smileSection(vars.cube.tenors.options[i], vars.cube.tenors.swaps[j]); for (int k = 0; k < strikes.Count; k++) { double strike = strikes[k]; double diff = spreadedVolCube.volatility(vars.cube.tenors.options[i], vars.cube.tenors.swaps[j], strike) - volCube.link.volatility(vars.cube.tenors.options[i], vars.cube.tenors.swaps[j], strike); if (Math.Abs(diff - spread.value()) > 1e-16) { QAssert.Fail("\ndiff!=spread in volatility method:" + "\nexpiry time = " + vars.cube.tenors.options[i] + "\nswap length = " + vars.cube.tenors.swaps[j] + "\n atm strike = " + (strike) + "\ndiff = " + diff + "\nspread = " + spread.value()); } diff = smileSectionBySpreadedCube.volatility(strike) - smileSectionByCube.volatility(strike); if (Math.Abs(diff - spread.value()) > 1e-16) { QAssert.Fail("\ndiff!=spread in smile section method:" + "\nexpiry time = " + vars.cube.tenors.options[i] + "\nswap length = " + vars.cube.tenors.swaps[j] + "\n atm strike = " + (strike) + "\ndiff = " + diff + "\nspread = " + spread.value()); } } } } //testing observability Flag f = new Flag(); spreadedVolCube.registerWith(f.update); volCube.link.update(); if (!f.isUp()) { QAssert.Fail("SpreadedSwaptionVolatilityStructure does not propagate notifications"); } f.lower(); spread.setValue(.001); if (!f.isUp()) { QAssert.Fail("SpreadedSwaptionVolatilityStructure does not propagate notifications"); } }
public void testMultiDimRegression() { //BOOST_MESSAGE("Testing linear least-squares regression..."); //SavedSettings backup; const int nr = 100000; const int dims = 4; const double tolerance = 0.01; var rng = new InverseCumulativeRng <MersenneTwisterUniformRng, InverseCumulativeNormal>( new MersenneTwisterUniformRng(1234u)); List <Func <Vector, double> > v = new List <Func <Vector, double> >(); v.Add(xx => 1.0); for (int i = 0; i < dims; ++i) { int jj = i; // c# delegate work-around vs. boost bind; jj has to be evaluted before add delegate to the list v.Add(vv => vv[jj]); } Vector coeff = new Vector(v.Count); for (int i = 0; i < v.Count; ++i) { coeff[i] = rng.next().value; } List <double> y = new InitializedList <double>(nr, 0.0); List <Vector> x = new InitializedList <Vector>(nr); for (int i = 0; i < nr; ++i) { x[i] = new Vector(dims); for (int j = 0; j < dims; ++j) { x[i][j] = rng.next().value; } for (int j = 0; j < v.Count; ++j) { y[i] += coeff[j] * v[j](x[i]); } y[i] += rng.next().value; } LinearLeastSquaresRegression <Vector> m = new LinearLeastSquaresRegression <Vector>(x, y, v); for (int i = 0; i < v.Count; ++i) { if (m.standardErrors()[i] > tolerance) { Assert.Fail("Failed to reproduce linear regression coef." + "\n error: " + m.standardErrors()[i] + "\n tolerance: " + tolerance); } if (Math.Abs(m.coefficients()[i] - coeff[i]) > 3 * tolerance) { Assert.Fail("Failed to reproduce linear regression coef." + "\n calculated: " + m.coefficients()[i] + "\n error: " + m.standardErrors()[i] + "\n expected: " + coeff[i]); } } }
public void testCallableEquityPricing() { // Testing the pricing of a callable equity product /* * For the definition of the example product see * Alexander Giese, On the Pricing of Auto-Callable Equity * Structures in the Presence of Stochastic Volatility and * Stochastic Interest Rates . * http://workshop.mathfinance.de/2006/papers/giese/slides.pdf */ int maturity = 7; DayCounter dc = new Actual365Fixed(); Date today = Date.Today; Settings.Instance.setEvaluationDate(today); Handle <Quote> spot = new Handle <Quote>(new SimpleQuote(100.0)); SimpleQuote qRate = new SimpleQuote(0.04); Handle <YieldTermStructure> qTS = new Handle <YieldTermStructure>(Utilities.flatRate(today, qRate, dc)); SimpleQuote rRate = new SimpleQuote(0.04); Handle <YieldTermStructure> rTS = new Handle <YieldTermStructure>(Utilities.flatRate(today, rRate, dc)); HestonProcess hestonProcess = new HestonProcess(rTS, qTS, spot, 0.0625, 1.0, 0.24 * 0.24, 1e-4, 0.0); // FLOATING_POINT_EXCEPTION HullWhiteForwardProcess hwProcess = new HullWhiteForwardProcess(rTS, 0.00883, 0.00526); hwProcess.setForwardMeasureTime(dc.yearFraction(today, today + new Period(maturity + 1, TimeUnit.Years))); HybridHestonHullWhiteProcess jointProcess = new HybridHestonHullWhiteProcess(hestonProcess, hwProcess, -0.4); Schedule schedule = new Schedule(today, today + new Period(maturity, TimeUnit.Years), new Period(1, TimeUnit.Years), new TARGET(), BusinessDayConvention.Following, BusinessDayConvention.Following, DateGeneration.Rule.Forward, false); List <double> times = new InitializedList <double>(maturity + 1); for (int i = 0; i <= maturity; ++i) { times[i] = i; } TimeGrid grid = new TimeGrid(times, times.Count); List <double> redemption = new InitializedList <double>(maturity); for (int i = 0; i < maturity; ++i) { redemption[i] = 1.07 + 0.03 * i; } ulong seed = 42; IRNG rsg = (InverseCumulativeRsg <RandomSequenceGenerator <MersenneTwisterUniformRng> , InverseCumulativeNormal>) new PseudoRandom().make_sequence_generator(jointProcess.factors() * (grid.size() - 1), seed); MultiPathGenerator <IRNG> generator = new MultiPathGenerator <IRNG>(jointProcess, grid, rsg, false); GeneralStatistics stat = new GeneralStatistics(); double antitheticPayoff = 0; int nrTrails = 40000; for (int i = 0; i < nrTrails; ++i) { bool antithetic = (i % 2) != 0; Sample <IPath> path = antithetic ? generator.antithetic() : generator.next(); MultiPath value = path.value as MultiPath; Utils.QL_REQUIRE(value != null, () => "Invalid Path"); double payoff = 0; for (int j = 1; j <= maturity; ++j) { if (value[0][j] > spot.link.value()) { Vector states = new Vector(3); for (int k = 0; k < 3; ++k) { states[k] = value[k][j]; } payoff = redemption[j - 1] / jointProcess.numeraire(grid[j], states); break; } else if (j == maturity) { Vector states = new Vector(3); for (int k = 0; k < 3; ++k) { states[k] = value[k][j]; } payoff = 1.0 / jointProcess.numeraire(grid[j], states); } } if (antithetic) { stat.add(0.5 * (antitheticPayoff + payoff)); } else { antitheticPayoff = payoff; } } double expected = 0.938; double calculated = stat.mean(); double error = stat.errorEstimate(); if (Math.Abs(expected - calculated) > 3 * error) { QAssert.Fail("Failed to reproduce auto-callable equity structure price" + "\n calculated: " + calculated + "\n error: " + error + "\n expected: " + expected); } }
public void testZeroBondPricing() { // Testing Monte-Carlo zero bond pricing DayCounter dc = new Actual360(); Date today = Date.Today; Settings.Instance.setEvaluationDate(today); // construct a strange yield curve to check drifts and discounting // of the joint stochastic process List <Date> dates = new List <Date>(); List <double> times = new List <double>(); List <double> rates = new List <double>(); dates.Add(today); rates.Add(0.02); times.Add(0.0); for (int i = 120; i < 240; ++i) { dates.Add(today + new Period(i, TimeUnit.Months)); rates.Add(0.02 + 0.0002 * Math.Exp(Math.Sin(i / 8.0))); times.Add(dc.yearFraction(today, dates.Last())); } Date maturity = dates.Last() + new Period(10, TimeUnit.Years); dates.Add(maturity); rates.Add(0.04); //times.Add(dc.yearFraction(today, dates.Last())); Handle <Quote> s0 = new Handle <Quote>(new SimpleQuote(100)); Handle <YieldTermStructure> ts = new Handle <YieldTermStructure>(new InterpolatedZeroCurve <Linear>(dates, rates, dc)); Handle <YieldTermStructure> ds = new Handle <YieldTermStructure>(Utilities.flatRate(today, 0.0, dc)); HestonProcess hestonProcess = new HestonProcess(ts, ds, s0, 0.02, 1.0, 0.2, 0.5, -0.8); HullWhiteForwardProcess hwProcess = new HullWhiteForwardProcess(ts, 0.05, 0.05); hwProcess.setForwardMeasureTime(dc.yearFraction(today, maturity)); HullWhite hwModel = new HullWhite(ts, 0.05, 0.05); HybridHestonHullWhiteProcess jointProcess = new HybridHestonHullWhiteProcess(hestonProcess, hwProcess, -0.4); TimeGrid grid = new TimeGrid(times); int factors = jointProcess.factors(); int steps = grid.size() - 1; SobolBrownianBridgeRsg rsg = new SobolBrownianBridgeRsg(factors, steps); MultiPathGenerator <SobolBrownianBridgeRsg> generator = new MultiPathGenerator <SobolBrownianBridgeRsg>( jointProcess, grid, rsg, false); int m = 90; List <GeneralStatistics> zeroStat = new InitializedList <GeneralStatistics>(m); List <GeneralStatistics> optionStat = new InitializedList <GeneralStatistics>(m); int nrTrails = 8191; int optionTenor = 24; double strike = 0.5; for (int i = 0; i < nrTrails; ++i) { Sample <IPath> path = generator.next(); MultiPath value = path.value as MultiPath; Utils.QL_REQUIRE(value != null, () => "Invalid Path"); for (int j = 1; j < m; ++j) { double t = grid[j]; // zero end and option maturity double T = grid[j + optionTenor]; // maturity of zero bond // of option Vector states = new Vector(3); Vector optionStates = new Vector(3); for (int k = 0; k < jointProcess.size(); ++k) { states[k] = value[k][j]; optionStates[k] = value[k][j + optionTenor]; } double zeroBond = 1.0 / jointProcess.numeraire(t, states); double zeroOption = zeroBond * Math.Max(0.0, hwModel.discountBond(t, T, states[2]) - strike); zeroStat[j].add(zeroBond); optionStat[j].add(zeroOption); } } for (int j = 1; j < m; ++j) { double t = grid[j]; double calculated = zeroStat[j].mean(); double expected = ts.link.discount(t); if (Math.Abs(calculated - expected) > 0.03) { QAssert.Fail("Failed to reproduce expected zero bond prices" + "\n t: " + t + "\n calculated: " + calculated + "\n expected: " + expected); } double T = grid[j + optionTenor]; calculated = optionStat[j].mean(); expected = hwModel.discountBondOption(Option.Type.Call, strike, t, T); if (Math.Abs(calculated - expected) > 0.0035) { QAssert.Fail("Failed to reproduce expected zero bond option prices" + "\n t: " + t + "\n T: " + T + "\n calculated: " + calculated + "\n expected: " + expected); } } }
public void cpibondconsistency() { CommonVars common = new CommonVars(); // ZeroInflationSwap aka CPISwap CPISwap.Type type = CPISwap.Type.Payer; double nominal = 1000000.0; bool subtractInflationNominal = true; // float+spread leg double spread = 0.0; DayCounter floatDayCount = new Actual365Fixed(); BusinessDayConvention floatPaymentConvention = BusinessDayConvention.ModifiedFollowing; int fixingDays = 0; IborIndex floatIndex = new GBPLibor(new Period(6, TimeUnit.Months), common.nominalUK); // fixed x inflation leg double fixedRate = 0.1; //1% would be 0.01 double baseCPI = 206.1; // would be 206.13871 if we were interpolating DayCounter fixedDayCount = new Actual365Fixed(); BusinessDayConvention fixedPaymentConvention = BusinessDayConvention.ModifiedFollowing; Calendar fixedPaymentCalendar = new UnitedKingdom(); ZeroInflationIndex fixedIndex = common.ii; Period contractObservationLag = common.contractObservationLag; InterpolationType observationInterpolation = common.contractObservationInterpolation; // set the schedules Date startDate = new Date(2, Month.October, 2007); Date endDate = new Date(2, Month.October, 2052); Schedule floatSchedule = new MakeSchedule().from(startDate).to(endDate) .withTenor(new Period(6, TimeUnit.Months)) .withCalendar(new UnitedKingdom()) .withConvention(floatPaymentConvention) .backwards().value(); Schedule fixedSchedule = new MakeSchedule().from(startDate).to(endDate) .withTenor(new Period(6, TimeUnit.Months)) .withCalendar(new UnitedKingdom()) .withConvention(BusinessDayConvention.Unadjusted) .backwards().value(); CPISwap zisV = new CPISwap(type, nominal, subtractInflationNominal, spread, floatDayCount, floatSchedule, floatPaymentConvention, fixingDays, floatIndex, fixedRate, baseCPI, fixedDayCount, fixedSchedule, fixedPaymentConvention, contractObservationLag, fixedIndex, observationInterpolation); double[] floatFix = { 0.06255, 0.05975, 0.0637, 0.018425, 0.0073438, -1, -1 }; double[] cpiFix = { 211.4, 217.2, 211.4, 213.4, -2, -2 }; for (int i = 0; i < floatSchedule.Count; i++) { if (floatSchedule[i] < common.evaluationDate) { floatIndex.addFixing(floatSchedule[i], floatFix[i], true);//true=overwrite } CPICoupon zic = zisV.cpiLeg()[i] as CPICoupon; if (zic != null) { if (zic.fixingDate() < (common.evaluationDate - new Period(1, TimeUnit.Months))) { fixedIndex.addFixing(zic.fixingDate(), cpiFix[i], true); } } } // simple structure so simple pricing engine - most work done by index DiscountingSwapEngine dse = new DiscountingSwapEngine(common.nominalUK); zisV.setPricingEngine(dse); // now do the bond equivalent List <double> fixedRates = new InitializedList <double>(1, fixedRate); int settlementDays = 1;// cannot be zero! bool growthOnly = true; CPIBond cpiB = new CPIBond(settlementDays, nominal, growthOnly, baseCPI, contractObservationLag, fixedIndex, observationInterpolation, fixedSchedule, fixedRates, fixedDayCount, fixedPaymentConvention); DiscountingBondEngine dbe = new DiscountingBondEngine(common.nominalUK); cpiB.setPricingEngine(dbe); QAssert.IsTrue(Math.Abs(cpiB.NPV() - zisV.legNPV(0).GetValueOrDefault()) < 1e-5, "cpi bond does not equal equivalent cpi swap leg"); // remove circular refernce common.hcpi.linkTo(null); }
public LoanPricingEngineResults() { legNPV = new InitializedList <double?>(); }
public void testSpreadDependency() { //"Testing swaption dependency on spread..."; CommonVars vars = new CommonVars(); double[] spreads = { -0.002, -0.001, 0.0, 0.001, 0.002 }; for (int i=0; i<exercises.Length ; i++) { for (int j=0; j<lengths.Length ; j++) { for (int k=0; k<type.Length ; k++) { Date exerciseDate = vars.calendar.advance(vars.today, exercises[i]); Date startDate = vars.calendar.advance(exerciseDate, vars.settlementDays,TimeUnit.Days); // store the results for different rates... List<double> values=new InitializedList<double>(spreads.Length); List<double> values_cash = new InitializedList<double>(spreads.Length); for (int l=0; l<spreads.Length; l++) { VanillaSwap swap = new MakeVanillaSwap(lengths[j], vars.index, 0.06) .withEffectiveDate(startDate) .withFloatingLegSpread(spreads[l]) .withType(type[k]); Swaption swaption = vars.makeSwaption(swap,exerciseDate,0.20); // FLOATING_POINT_EXCEPTION values[l]=swaption.NPV(); Swaption swaption_cash = vars.makeSwaption(swap,exerciseDate,0.20, Settlement.Type.Cash); values_cash[l]=swaption_cash.NPV(); } // and check that they go the right way if (type[k]==VanillaSwap.Type.Payer) { for (int n = 0; n < spreads.Length - 1; n++) { if (values[n] > values[n + 1]) Assert.Fail("NPV is decreasing with the spread " + "in a payer swaption (physical delivered):" + "\nexercise date: " + exerciseDate + "\nlength: " + lengths[j] + "\nvalue: " + values[n] + " for spread: " + spreads[n] + "\nvalue: " + values[n + 1] + " for spread: " + spreads[n + 1]); if (values_cash[n] > values_cash[n + 1]) Assert.Fail("NPV is decreasing with the spread " + "in a payer swaption (cash delivered):" + "\nexercise date: " + exerciseDate + "\nlength: " + lengths[j] + "\nvalue: " + values_cash[n] + " for spread: " + spreads[n] + "\nvalue: " + values_cash[n + 1] + " for spread: " + spreads[n + 1]); } } else { for (int n = 0; n < spreads.Length - 1; n++) { if (values[n] < values[n + 1]) Assert.Fail("NPV is increasing with the spread " + "in a receiver swaption (physical delivered):" + "\nexercise date: " + exerciseDate + "\nlength: " + lengths[j] + "\nvalue: " + values[n] + " for spread: " + spreads[n] + "\nvalue: " + values[n + 1] + " for spread: " + spreads[n + 1]); if (values_cash[n] < values_cash[n+1]) Assert.Fail("NPV is increasing with the spread " + "in a receiver swaption (cash delivered):" + "\nexercise date: " + exerciseDate + "\nlength: " + lengths[j] + "\nvalue: " + values_cash[n ] + " for spread: " + spreads[n] + "\nvalue: " + values_cash[n+1] + " for spread: " + spreads[n+1]); } } } } } }
public void testSwaptionPricing() { // Testing forward swap and swaption pricing 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, tmp.Count, 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) { QAssert.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 <IPath> path = (n % 2 != 0) ? generator.antithetic() : generator.next(); MultiPath value = path.value as MultiPath; Utils.QL_REQUIRE(value != null, () => "Invalid Path"); //Sample<MultiPath> path = generator.next(); List <double> rates_ = new InitializedList <double>(size); for (int k = 0; k < process.size(); ++k) { rates_[k] = 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) { QAssert.Fail("Failed to reproduce swaption npv" + "\n calculated: " + stat.mean() + "\n expected: " + swaption.NPV()); } } } } }
public void testBrazilianCached() { //("Testing Brazilian public bond prices against cached values..."); CommonVars vars = new CommonVars(); double faceAmount = 1000.0; double redemption = 100.0; Date issueDate = new Date(1, Month.January, 2007); Date today = new Date(6, Month.June, 2007); Settings.setEvaluationDate(today); // NTN-F maturity dates InitializedList<Date> maturityDates = new InitializedList<Date>(6); maturityDates[0] = new Date(1, Month.January, 2008); maturityDates[1] = new Date(1, Month.January, 2010); maturityDates[2] = new Date(1, Month.July, 2010); maturityDates[3] = new Date(1, Month.January, 2012); maturityDates[4] = new Date(1, Month.January, 2014); maturityDates[5] = new Date(1, Month.January, 2017); // NTN-F yields InitializedList<double> yields = new InitializedList<double>(6); yields[0] = 0.114614; yields[1] = 0.105726; yields[2] = 0.105328; yields[3] = 0.104283; yields[4] = 0.103218; yields[5] = 0.102948; // NTN-F prices InitializedList<double> prices = new InitializedList<double>(6); prices[0] = 1034.63031372; prices[1] = 1030.09919487; prices[2] = 1029.98307160; prices[3] = 1028.13585068; prices[4] = 1028.33383817; prices[5] = 1026.19716497; int settlementDays = 1; vars.faceAmount = 1000.0; // The tolerance is high because Andima truncate yields double tolerance = 1.0e-4; InitializedList<InterestRate> couponRates = new InitializedList<InterestRate>(1); couponRates[0] = new InterestRate(0.1, new Thirty360(), Compounding.Compounded, Frequency.Annual); for (int bondIndex = 0; bondIndex < maturityDates.Count; bondIndex++) { // plain InterestRate yield = new InterestRate(yields[bondIndex], new Business252(new Brazil()), Compounding.Compounded, Frequency.Annual); Schedule schedule = new Schedule(new Date(1, Month.January, 2007), maturityDates[bondIndex], new Period(Frequency.Semiannual), new Brazil(Brazil.Market.Settlement), BusinessDayConvention.Unadjusted, BusinessDayConvention.Unadjusted, DateGeneration.Rule.Backward, false); FixedRateBond bond = new FixedRateBond(settlementDays, faceAmount, schedule, couponRates, BusinessDayConvention.Following, redemption, issueDate); double cachedPrice = prices[bondIndex]; double price = vars.faceAmount * (bond.cleanPrice(yield.rate(), yield.dayCounter(), yield.compounding(), yield.frequency(), today) + bond.accruedAmount(today)) / 100; if (Math.Abs(price - cachedPrice) > tolerance) { Assert.Fail("failed to reproduce cached price:\n" + " calculated: " + price + "\n" + " expected: " + cachedPrice + "\n" + " error: " + (price - cachedPrice) + "\n" ); } } }
static void Main(string[] args) { DateTime timer = DateTime.Now; /********************* *** MARKET DATA *** *********************/ Calendar calendar = new TARGET(); Date settlementDate = new Date(18, Month.September, 2008); // must be a business day settlementDate = calendar.adjust(settlementDate); int fixingDays = 3; int settlementDays = 3; Date todaysDate = calendar.advance(settlementDate, -fixingDays, TimeUnit.Days); // nothing to do with Date::todaysDate Settings.setEvaluationDate(todaysDate); Console.WriteLine("Today: {0}, {1}", todaysDate.DayOfWeek, todaysDate); Console.WriteLine("Settlement date: {0}, {1}", settlementDate.DayOfWeek, settlementDate); // Building of the bonds discounting yield curve /********************* *** RATE HELPERS *** *********************/ // RateHelpers are built from the above quotes together with // other instrument dependant infos. Quotes are passed in // relinkable handles which could be relinked to some other // data source later. // Common data // ZC rates for the short end double zc3mQuote = 0.0096; double zc6mQuote = 0.0145; double zc1yQuote = 0.0194; Quote zc3mRate = new SimpleQuote(zc3mQuote); Quote zc6mRate = new SimpleQuote(zc6mQuote); Quote zc1yRate = new SimpleQuote(zc1yQuote); DayCounter zcBondsDayCounter = new Actual365Fixed(); RateHelper zc3m = new DepositRateHelper(new Handle <Quote>(zc3mRate), new Period(3, TimeUnit.Months), fixingDays, calendar, BusinessDayConvention.ModifiedFollowing, true, zcBondsDayCounter); RateHelper zc6m = new DepositRateHelper(new Handle <Quote>(zc6mRate), new Period(6, TimeUnit.Months), fixingDays, calendar, BusinessDayConvention.ModifiedFollowing, true, zcBondsDayCounter); RateHelper zc1y = new DepositRateHelper(new Handle <Quote>(zc1yRate), new Period(1, TimeUnit.Years), fixingDays, calendar, BusinessDayConvention.ModifiedFollowing, true, zcBondsDayCounter); // setup bonds double redemption = 100.0; const int numberOfBonds = 5; Date[] issueDates = { new Date(15, Month.March, 2005), new Date(15, Month.June, 2005), new Date(30, Month.June, 2006), new Date(15, Month.November, 2002), new Date(15, Month.May, 1987) }; Date[] maturities = { new Date(31, Month.August, 2010), new Date(31, Month.August, 2011), new Date(31, Month.August, 2013), new Date(15, Month.August, 2018), new Date(15, Month.May, 2038) }; double[] couponRates = { 0.02375, 0.04625, 0.03125, 0.04000, 0.04500 }; double[] marketQuotes = { 100.390625, 106.21875, 100.59375, 101.6875, 102.140625 }; List <SimpleQuote> quote = new List <SimpleQuote>(); for (int i = 0; i < numberOfBonds; i++) { SimpleQuote cp = new SimpleQuote(marketQuotes[i]); quote.Add(cp); } List <RelinkableHandle <Quote> > quoteHandle = new InitializedList <RelinkableHandle <Quote> >(numberOfBonds); for (int i = 0; i < numberOfBonds; i++) { quoteHandle[i].linkTo(quote[i]); } // Definition of the rate helpers List <FixedRateBondHelper> bondsHelpers = new List <FixedRateBondHelper>(); for (int i = 0; i < numberOfBonds; i++) { Schedule schedule = new Schedule(issueDates[i], maturities[i], new Period(Frequency.Semiannual), new UnitedStates(UnitedStates.Market.GovernmentBond), BusinessDayConvention.Unadjusted, BusinessDayConvention.Unadjusted, DateGeneration.Rule.Backward, false); FixedRateBondHelper bondHelper = new FixedRateBondHelper(quoteHandle[i], settlementDays, 100.0, schedule, new List <double>() { couponRates[i] }, new ActualActual(ActualActual.Convention.Bond), BusinessDayConvention.Unadjusted, redemption, issueDates[i]); bondsHelpers.Add(bondHelper); } /********************* ** CURVE BUILDING ** *********************/ // Any DayCounter would be fine. // ActualActual::ISDA ensures that 30 years is 30.0 DayCounter termStructureDayCounter = new ActualActual(ActualActual.Convention.ISDA); double tolerance = 1.0e-15; // A depo-bond curve List <RateHelper> bondInstruments = new List <RateHelper>(); // Adding the ZC bonds to the curve for the short end bondInstruments.Add(zc3m); bondInstruments.Add(zc6m); bondInstruments.Add(zc1y); // Adding the Fixed rate bonds to the curve for the long end for (int i = 0; i < numberOfBonds; i++) { bondInstruments.Add(bondsHelpers[i]); } YieldTermStructure bondDiscountingTermStructure = new PiecewiseYieldCurve <Discount, LogLinear>( settlementDate, bondInstruments, termStructureDayCounter, new List <Handle <Quote> >(), new List <Date>(), tolerance); // Building of the Libor forecasting curve // deposits double d1wQuote = 0.043375; double d1mQuote = 0.031875; double d3mQuote = 0.0320375; double d6mQuote = 0.03385; double d9mQuote = 0.0338125; double d1yQuote = 0.0335125; // swaps double s2yQuote = 0.0295; double s3yQuote = 0.0323; double s5yQuote = 0.0359; double s10yQuote = 0.0412; double s15yQuote = 0.0433; /******************** *** QUOTES *** ********************/ // SimpleQuote stores a value which can be manually changed; // other Quote subclasses could read the value from a database // or some kind of data feed. // deposits Quote d1wRate = new SimpleQuote(d1wQuote); Quote d1mRate = new SimpleQuote(d1mQuote); Quote d3mRate = new SimpleQuote(d3mQuote); Quote d6mRate = new SimpleQuote(d6mQuote); Quote d9mRate = new SimpleQuote(d9mQuote); Quote d1yRate = new SimpleQuote(d1yQuote); // swaps Quote s2yRate = new SimpleQuote(s2yQuote); Quote s3yRate = new SimpleQuote(s3yQuote); Quote s5yRate = new SimpleQuote(s5yQuote); Quote s10yRate = new SimpleQuote(s10yQuote); Quote s15yRate = new SimpleQuote(s15yQuote); /********************* *** RATE HELPERS *** *********************/ // RateHelpers are built from the above quotes together with // other instrument dependant infos. Quotes are passed in // relinkable handles which could be relinked to some other // data source later. // deposits DayCounter depositDayCounter = new Actual360(); RateHelper d1w = new DepositRateHelper( new Handle <Quote>(d1wRate), new Period(1, TimeUnit.Weeks), fixingDays, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); RateHelper d1m = new DepositRateHelper( new Handle <Quote>(d1mRate), new Period(1, TimeUnit.Months), fixingDays, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); RateHelper d3m = new DepositRateHelper( new Handle <Quote>(d3mRate), new Period(3, TimeUnit.Months), fixingDays, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); RateHelper d6m = new DepositRateHelper( new Handle <Quote>(d6mRate), new Period(6, TimeUnit.Months), fixingDays, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); RateHelper d9m = new DepositRateHelper( new Handle <Quote>(d9mRate), new Period(9, TimeUnit.Months), fixingDays, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); RateHelper d1y = new DepositRateHelper( new Handle <Quote>(d1yRate), new Period(1, TimeUnit.Years), fixingDays, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); // setup swaps Frequency swFixedLegFrequency = Frequency.Annual; BusinessDayConvention swFixedLegConvention = BusinessDayConvention.Unadjusted; DayCounter swFixedLegDayCounter = new Thirty360(Thirty360.Thirty360Convention.European); IborIndex swFloatingLegIndex = new Euribor6M(); Period forwardStart = new Period(1, TimeUnit.Days); RateHelper s2y = new SwapRateHelper( new Handle <Quote>(s2yRate), new Period(2, TimeUnit.Years), calendar, swFixedLegFrequency, swFixedLegConvention, swFixedLegDayCounter, swFloatingLegIndex, new Handle <Quote>(), forwardStart); RateHelper s3y = new SwapRateHelper( new Handle <Quote>(s3yRate), new Period(3, TimeUnit.Years), calendar, swFixedLegFrequency, swFixedLegConvention, swFixedLegDayCounter, swFloatingLegIndex, new Handle <Quote>(), forwardStart); RateHelper s5y = new SwapRateHelper( new Handle <Quote>(s5yRate), new Period(5, TimeUnit.Years), calendar, swFixedLegFrequency, swFixedLegConvention, swFixedLegDayCounter, swFloatingLegIndex, new Handle <Quote>(), forwardStart); RateHelper s10y = new SwapRateHelper( new Handle <Quote>(s10yRate), new Period(10, TimeUnit.Years), calendar, swFixedLegFrequency, swFixedLegConvention, swFixedLegDayCounter, swFloatingLegIndex, new Handle <Quote>(), forwardStart); RateHelper s15y = new SwapRateHelper( new Handle <Quote>(s15yRate), new Period(15, TimeUnit.Years), calendar, swFixedLegFrequency, swFixedLegConvention, swFixedLegDayCounter, swFloatingLegIndex, new Handle <Quote>(), forwardStart); /********************* ** CURVE BUILDING ** *********************/ // Any DayCounter would be fine. // ActualActual::ISDA ensures that 30 years is 30.0 // A depo-swap curve List <RateHelper> depoSwapInstruments = new List <RateHelper>(); depoSwapInstruments.Add(d1w); depoSwapInstruments.Add(d1m); depoSwapInstruments.Add(d3m); depoSwapInstruments.Add(d6m); depoSwapInstruments.Add(d9m); depoSwapInstruments.Add(d1y); depoSwapInstruments.Add(s2y); depoSwapInstruments.Add(s3y); depoSwapInstruments.Add(s5y); depoSwapInstruments.Add(s10y); depoSwapInstruments.Add(s15y); YieldTermStructure depoSwapTermStructure = new PiecewiseYieldCurve <Discount, LogLinear>( settlementDate, depoSwapInstruments, termStructureDayCounter, new List <Handle <Quote> >(), new List <Date>(), tolerance); // Term structures that will be used for pricing: // the one used for discounting cash flows RelinkableHandle <YieldTermStructure> discountingTermStructure = new RelinkableHandle <YieldTermStructure>(); // the one used for forward rate forecasting RelinkableHandle <YieldTermStructure> forecastingTermStructure = new RelinkableHandle <YieldTermStructure>(); /********************* * BONDS TO BE PRICED * **********************/ // Common data double faceAmount = 100; // Pricing engine IPricingEngine bondEngine = new DiscountingBondEngine(discountingTermStructure); // Zero coupon bond ZeroCouponBond zeroCouponBond = new ZeroCouponBond( settlementDays, new UnitedStates(UnitedStates.Market.GovernmentBond), faceAmount, new Date(15, Month.August, 2013), BusinessDayConvention.Following, 116.92, new Date(15, Month.August, 2003)); zeroCouponBond.setPricingEngine(bondEngine); // Fixed 4.5% US Treasury Note Schedule fixedBondSchedule = new Schedule(new Date(15, Month.May, 2007), new Date(15, Month.May, 2017), new Period(Frequency.Semiannual), new UnitedStates(UnitedStates.Market.GovernmentBond), BusinessDayConvention.Unadjusted, BusinessDayConvention.Unadjusted, DateGeneration.Rule.Backward, false); FixedRateBond fixedRateBond = new FixedRateBond( settlementDays, faceAmount, fixedBondSchedule, new List <double>() { 0.045 }, new ActualActual(ActualActual.Convention.Bond), BusinessDayConvention.ModifiedFollowing, 100.0, new Date(15, Month.May, 2007)); fixedRateBond.setPricingEngine(bondEngine); // Floating rate bond (3M USD Libor + 0.1%) // Should and will be priced on another curve later... RelinkableHandle <YieldTermStructure> liborTermStructure = new RelinkableHandle <YieldTermStructure>(); IborIndex libor3m = new USDLibor(new Period(3, TimeUnit.Months), liborTermStructure); libor3m.addFixing(new Date(17, Month.July, 2008), 0.0278625); Schedule floatingBondSchedule = new Schedule(new Date(21, Month.October, 2005), new Date(21, Month.October, 2010), new Period(Frequency.Quarterly), new UnitedStates(UnitedStates.Market.NYSE), BusinessDayConvention.Unadjusted, BusinessDayConvention.Unadjusted, DateGeneration.Rule.Backward, true); FloatingRateBond floatingRateBond = new FloatingRateBond( settlementDays, faceAmount, floatingBondSchedule, libor3m, new Actual360(), BusinessDayConvention.ModifiedFollowing, 2, // Gearings new List <double>() { 1.0 }, // Spreads new List <double>() { 0.001 }, // Caps new List <double?>(), // Floors new List <double?>(), // Fixing in arrears true, 100.0, new Date(21, Month.October, 2005)); floatingRateBond.setPricingEngine(bondEngine); // Coupon pricers IborCouponPricer pricer = new BlackIborCouponPricer(); // optionLet volatilities double volatility = 0.0; Handle <OptionletVolatilityStructure> vol; vol = new Handle <OptionletVolatilityStructure>( new ConstantOptionletVolatility( settlementDays, calendar, BusinessDayConvention.ModifiedFollowing, volatility, new Actual365Fixed())); pricer.setCapletVolatility(vol); Utils.setCouponPricer(floatingRateBond.cashflows(), pricer); // Yield curve bootstrapping forecastingTermStructure.linkTo(depoSwapTermStructure); discountingTermStructure.linkTo(bondDiscountingTermStructure); // We are using the depo & swap curve to estimate the future Libor rates liborTermStructure.linkTo(depoSwapTermStructure); /*************** * BOND PRICING * ****************/ // write column headings int[] widths = { 18, 10, 10, 10 }; Console.WriteLine("{0,18}{1,10}{2,10}{3,10}", "", "ZC", "Fixed", "Floating"); int width = widths[0] + widths[1] + widths[2] + widths[3]; string rule = "".PadLeft(width, '-'), dblrule = "".PadLeft(width, '='); string tab = "".PadLeft(8, ' '); Console.WriteLine(rule); Console.WriteLine("Net present value".PadLeft(widths[0]) + "{0,10:n2}{1,10:n2}{2,10:n2}", zeroCouponBond.NPV(), fixedRateBond.NPV(), floatingRateBond.NPV()); Console.WriteLine("Clean price".PadLeft(widths[0]) + "{0,10:n2}{1,10:n2}{2,10:n2}", zeroCouponBond.cleanPrice(), fixedRateBond.cleanPrice(), floatingRateBond.cleanPrice()); Console.WriteLine("Dirty price".PadLeft(widths[0]) + "{0,10:n2}{1,10:n2}{2,10:n2}", zeroCouponBond.dirtyPrice(), fixedRateBond.dirtyPrice(), floatingRateBond.dirtyPrice()); Console.WriteLine("Accrued coupon".PadLeft(widths[0]) + "{0,10:n2}{1,10:n2}{2,10:n2}", zeroCouponBond.accruedAmount(), fixedRateBond.accruedAmount(), floatingRateBond.accruedAmount()); Console.WriteLine("Previous coupon".PadLeft(widths[0]) + "{0,10:0.00%}{1,10:0.00%}{2,10:0.00%}", "N/A", fixedRateBond.previousCouponRate(), floatingRateBond.previousCouponRate()); Console.WriteLine("Next coupon".PadLeft(widths[0]) + "{0,10:0.00%}{1,10:0.00%}{2,10:0.00%}", "N/A", fixedRateBond.nextCouponRate(), floatingRateBond.nextCouponRate()); Console.WriteLine("Yield".PadLeft(widths[0]) + "{0,10:0.00%}{1,10:0.00%}{2,10:0.00%}", zeroCouponBond.yield(new Actual360(), Compounding.Compounded, Frequency.Annual), fixedRateBond.yield(new Actual360(), Compounding.Compounded, Frequency.Annual), floatingRateBond.yield(new Actual360(), Compounding.Compounded, Frequency.Annual)); Console.WriteLine(); // Other computations Console.WriteLine("Sample indirect computations (for the floating rate bond): "); Console.WriteLine(rule); Console.WriteLine("Yield to Clean Price: {0:n2}", floatingRateBond.cleanPrice(floatingRateBond.yield(new Actual360(), Compounding.Compounded, Frequency.Annual), new Actual360(), Compounding.Compounded, Frequency.Annual, settlementDate)); Console.WriteLine("Clean Price to Yield: {0:0.00%}", floatingRateBond.yield(floatingRateBond.cleanPrice(), new Actual360(), Compounding.Compounded, Frequency.Annual, settlementDate)); /* "Yield to Price" * "Price to Yield" */ Console.WriteLine(" \nRun completed in {0}", DateTime.Now - timer); Console.WriteLine(); Console.Write("Press any key to continue ..."); Console.ReadKey(); }
public void testCachedFloating() { // "Testing floating-rate bond prices against cached values..."); CommonVars vars = new CommonVars(); Date today = new Date(22, Month.November, 2004); Settings.setEvaluationDate(today); int settlementDays = 1; var riskFreeRate = new Handle<YieldTermStructure>(Utilities.flatRate(today, 0.025, new Actual360())); var discountCurve = new Handle<YieldTermStructure>(Utilities.flatRate(today, 0.03, new Actual360())); IborIndex index = new USDLibor(new Period(6, TimeUnit.Months), riskFreeRate); int fixingDays = 1; double tolerance = 1.0e-6; IborCouponPricer pricer = new BlackIborCouponPricer(new Handle<OptionletVolatilityStructure>()); // plain Schedule sch = new Schedule(new Date(30, Month.November, 2004), new Date(30, Month.November, 2008), new Period(Frequency.Semiannual), new UnitedStates(UnitedStates.Market.GovernmentBond), BusinessDayConvention.ModifiedFollowing, BusinessDayConvention.ModifiedFollowing, DateGeneration.Rule.Backward, false); FloatingRateBond bond1 = new FloatingRateBond(settlementDays, vars.faceAmount, sch, index, new ActualActual(ActualActual.Convention.ISMA), BusinessDayConvention.ModifiedFollowing, fixingDays, new List<double>(), new List<double>(), new List<double>(), new List<double>(), false, 100.0, new Date(30, Month.November, 2004)); IPricingEngine bondEngine = new DiscountingBondEngine(riskFreeRate); bond1.setPricingEngine(bondEngine); Utils.setCouponPricer(bond1.cashflows(), pricer); #if QL_USE_INDEXED_COUPON double cachedPrice1 = 99.874645; #else double cachedPrice1 = 99.874646; #endif double price = bond1.cleanPrice(); if (Math.Abs(price - cachedPrice1) > tolerance) { Assert.Fail("failed to reproduce cached price:\n" + " calculated: " + price + "\n" + " expected: " + cachedPrice1 + "\n" + " error: " + (price - cachedPrice1)); } // different risk-free and discount curve FloatingRateBond bond2 = new FloatingRateBond(settlementDays, vars.faceAmount, sch, index, new ActualActual(ActualActual.Convention.ISMA), BusinessDayConvention.ModifiedFollowing, fixingDays, new List<double>(), new List<double>(), new List<double>(), new List<double>(), false, 100.0, new Date(30, Month.November, 2004)); IPricingEngine bondEngine2 = new DiscountingBondEngine(discountCurve); bond2.setPricingEngine(bondEngine2); Utils.setCouponPricer(bond2.cashflows(), pricer); #if QL_USE_INDEXED_COUPON double cachedPrice2 = 97.955904; #else double cachedPrice2 = 97.955904; #endif price = bond2.cleanPrice(); if (Math.Abs(price - cachedPrice2) > tolerance) { Assert.Fail("failed to reproduce cached price:\n" + " calculated: " + price + "\n" + " expected: " + cachedPrice2 + "\n" + " error: " + (price - cachedPrice2)); } // varying spread InitializedList<double> spreads = new InitializedList<double>(4); spreads[0] = 0.001; spreads[1] = 0.0012; spreads[2] = 0.0014; spreads[3] = 0.0016; FloatingRateBond bond3 = new FloatingRateBond(settlementDays, vars.faceAmount, sch, index, new ActualActual(ActualActual.Convention.ISMA), BusinessDayConvention.ModifiedFollowing, fixingDays, new List<double>(), spreads, new List<double>(), new List<double>(), false, 100.0, new Date(30, Month.November, 2004)); bond3.setPricingEngine(bondEngine2); Utils.setCouponPricer(bond3.cashflows(), pricer); #if QL_USE_INDEXED_COUPON double cachedPrice3 = 98.495458; #else double cachedPrice3 = 98.495459; #endif price = bond3.cleanPrice(); if (Math.Abs(price - cachedPrice3) > tolerance) { Assert.Fail("failed to reproduce cached price:\n" + " calculated: " + price + "\n" + " expected: " + cachedPrice3 + "\n" + " error: " + (price - cachedPrice3)); } }
public void testDecomposition() { // Testing collared coupon against its decomposition... CommonVars vars = new CommonVars(); double tolerance = 1e-10; double npvVanilla, npvCappedLeg, npvFlooredLeg, npvCollaredLeg, npvCap, npvFloor, npvCollar; double error; double floorstrike = 0.05; double capstrike = 0.10; List <double> caps = new InitializedList <double>(vars.length, capstrike); List <double> caps0 = new List <double>(); List <double> floors = new InitializedList <double>(vars.length, floorstrike); List <double> floors0 = new List <double>(); double gearing_p = 0.5; double spread_p = 0.002; double gearing_n = -1.5; double spread_n = 0.12; // fixed leg with zero rate List <CashFlow> fixedLeg = vars.makeFixedLeg(vars.startDate, vars.length); // floating leg with gearing=1 and spread=0 List <CashFlow> floatLeg = vars.makeYoYLeg(vars.startDate, vars.length); // floating leg with positive gearing (gearing_p) and spread<>0 List <CashFlow> floatLeg_p = vars.makeYoYLeg(vars.startDate, vars.length, gearing_p, spread_p); // floating leg with negative gearing (gearing_n) and spread<>0 List <CashFlow> floatLeg_n = vars.makeYoYLeg(vars.startDate, vars.length, gearing_n, spread_n); // Swap with null fixed leg and floating leg with gearing=1 and spread=0 Swap vanillaLeg = new Swap(fixedLeg, floatLeg); // Swap with null fixed leg and floating leg with positive gearing and spread<>0 Swap vanillaLeg_p = new Swap(fixedLeg, floatLeg_p); // Swap with null fixed leg and floating leg with negative gearing and spread<>0 Swap vanillaLeg_n = new Swap(fixedLeg, floatLeg_n); IPricingEngine engine = new DiscountingSwapEngine(vars.nominalTS); vanillaLeg.setPricingEngine(engine); // here use the autoset feature vanillaLeg_p.setPricingEngine(engine); vanillaLeg_n.setPricingEngine(engine); // CAPPED coupon - Decomposition of payoff // Payoff = Nom * Min(rate,strike) * accrualperiod = // = Nom * [rate + Min(0,strike-rate)] * accrualperiod = // = Nom * rate * accrualperiod - Nom * Max(rate-strike,0) * accrualperiod = // = VanillaFloatingLeg - Call // int whichPricer = 0; // Case gearing = 1 and spread = 0 List <CashFlow> cappedLeg = vars.makeYoYCapFlooredLeg(whichPricer, vars.startDate, vars.length, caps, floors0, vars.volatility); Swap capLeg = new Swap(fixedLeg, cappedLeg); capLeg.setPricingEngine(engine); YoYInflationCap cap = new YoYInflationCap(floatLeg, new List <double>() { capstrike }); cap.setPricingEngine(vars.makeEngine(vars.volatility, whichPricer)); npvVanilla = vanillaLeg.NPV(); npvCappedLeg = capLeg.NPV(); npvCap = cap.NPV(); error = Math.Abs(npvCappedLeg - (npvVanilla - npvCap)); if (error > tolerance) { QAssert.Fail("\nYoY Capped Leg: gearing=1, spread=0%, strike=" + capstrike * 100 + "%\n" + " Capped Floating Leg NPV: " + npvCappedLeg + "\n" + " Floating Leg NPV - Cap NPV: " + (npvVanilla - npvCap) + "\n" + " Diff: " + error); } // gearing = 1 and spread = 0 // FLOORED coupon - Decomposition of payoff // Payoff = Nom * Max(rate,strike) * accrualperiod = // = Nom * [rate + Max(0,strike-rate)] * accrualperiod = // = Nom * rate * accrualperiod + Nom * Max(strike-rate,0) * accrualperiod = // = VanillaFloatingLeg + Put // List <CashFlow> flooredLeg = vars.makeYoYCapFlooredLeg(whichPricer, vars.startDate, vars.length, caps0, floors, vars.volatility); Swap floorLeg = new Swap(fixedLeg, flooredLeg); floorLeg.setPricingEngine(engine); YoYInflationFloor floor = new YoYInflationFloor(floatLeg, new List <double>() { floorstrike }); floor.setPricingEngine(vars.makeEngine(vars.volatility, whichPricer)); npvFlooredLeg = floorLeg.NPV(); npvFloor = floor.NPV(); error = Math.Abs(npvFlooredLeg - (npvVanilla + npvFloor)); if (error > tolerance) { QAssert.Fail("YoY Floored Leg: gearing=1, spread=0%, strike=" + floorstrike * 100 + "%\n" + " Floored Floating Leg NPV: " + npvFlooredLeg + "\n" + " Floating Leg NPV + Floor NPV: " + (npvVanilla + npvFloor) + "\n" + " Diff: " + error); } // gearing = 1 and spread = 0 // COLLARED coupon - Decomposition of payoff // Payoff = Nom * Min(strikem,Max(rate,strikeM)) * accrualperiod = // = VanillaFloatingLeg - Collar // List <CashFlow> collaredLeg = vars.makeYoYCapFlooredLeg(whichPricer, vars.startDate, vars.length, caps, floors, vars.volatility); Swap collarLeg = new Swap(fixedLeg, collaredLeg); collarLeg.setPricingEngine(engine); YoYInflationCollar collar = new YoYInflationCollar(floatLeg, new List <double>() { capstrike }, new List <double>() { floorstrike }); collar.setPricingEngine(vars.makeEngine(vars.volatility, whichPricer)); npvCollaredLeg = collarLeg.NPV(); npvCollar = collar.NPV(); error = Math.Abs(npvCollaredLeg - (npvVanilla - npvCollar)); if (error > tolerance) { QAssert.Fail("\nYoY Collared Leg: gearing=1, spread=0%, strike=" + floorstrike * 100 + "% and " + capstrike * 100 + "%\n" + " Collared Floating Leg NPV: " + npvCollaredLeg + "\n" + " Floating Leg NPV - Collar NPV: " + (npvVanilla - npvCollar) + "\n" + " Diff: " + error); } // gearing = a and spread = b // CAPPED coupon - Decomposition of payoff // Payoff // = Nom * Min(a*rate+b,strike) * accrualperiod = // = Nom * [a*rate+b + Min(0,strike-a*rate-b)] * accrualperiod = // = Nom * a*rate+b * accrualperiod + Nom * Min(strike-b-a*rate,0) * accrualperiod // --> If a>0 (assuming positive effective strike): // Payoff = VanillaFloatingLeg - Call(a*rate+b,strike) // --> If a<0 (assuming positive effective strike): // Payoff = VanillaFloatingLeg + Nom * Min(strike-b+|a|*rate+,0) * accrualperiod = // = VanillaFloatingLeg + Put(|a|*rate+b,strike) // // Positive gearing List <CashFlow> cappedLeg_p = vars.makeYoYCapFlooredLeg(whichPricer, vars.startDate, vars.length, caps, floors0, vars.volatility, gearing_p, spread_p); Swap capLeg_p = new Swap(fixedLeg, cappedLeg_p); capLeg_p.setPricingEngine(engine); YoYInflationCap cap_p = new YoYInflationCap(floatLeg_p, new List <double>() { capstrike }); cap_p.setPricingEngine(vars.makeEngine(vars.volatility, whichPricer)); npvVanilla = vanillaLeg_p.NPV(); npvCappedLeg = capLeg_p.NPV(); npvCap = cap_p.NPV(); error = Math.Abs(npvCappedLeg - (npvVanilla - npvCap)); if (error > tolerance) { QAssert.Fail("\nYoY Capped Leg: gearing=" + gearing_p + ", " + "spread= " + spread_p * 100 + "%, strike=" + capstrike * 100 + "%, " + "effective strike= " + (capstrike - spread_p) / gearing_p * 100 + "%\n" + " Capped Floating Leg NPV: " + npvCappedLeg + "\n" + " Vanilla Leg NPV: " + npvVanilla + "\n" + " Cap NPV: " + npvCap + "\n" + " Floating Leg NPV - Cap NPV: " + (npvVanilla - npvCap) + "\n" + " Diff: " + error); } // Negative gearing List <CashFlow> cappedLeg_n = vars.makeYoYCapFlooredLeg(whichPricer, vars.startDate, vars.length, caps, floors0, vars.volatility, gearing_n, spread_n); Swap capLeg_n = new Swap(fixedLeg, cappedLeg_n); capLeg_n.setPricingEngine(engine); YoYInflationFloor floor_n = new YoYInflationFloor(floatLeg, new List <double>() { (capstrike - spread_n) / gearing_n }); floor_n.setPricingEngine(vars.makeEngine(vars.volatility, whichPricer)); npvVanilla = vanillaLeg_n.NPV(); npvCappedLeg = capLeg_n.NPV(); npvFloor = floor_n.NPV(); error = Math.Abs(npvCappedLeg - (npvVanilla + gearing_n * npvFloor)); if (error > tolerance) { QAssert.Fail("\nYoY Capped Leg: gearing=" + gearing_n + ", " + "spread= " + spread_n * 100 + "%, strike=" + capstrike * 100 + "%, " + "effective strike= " + ((capstrike - spread_n) / gearing_n * 100) + "%\n" + " Capped Floating Leg NPV: " + npvCappedLeg + "\n" + " npv Vanilla: " + npvVanilla + "\n" + " npvFloor: " + npvFloor + "\n" + " Floating Leg NPV - Cap NPV: " + (npvVanilla + gearing_n * npvFloor) + "\n" + " Diff: " + error); } // gearing = a and spread = b // FLOORED coupon - Decomposition of payoff // Payoff // = Nom * Max(a*rate+b,strike) * accrualperiod = // = Nom * [a*rate+b + Max(0,strike-a*rate-b)] * accrualperiod = // = Nom * a*rate+b * accrualperiod + Nom * Max(strike-b-a*rate,0) * accrualperiod // --> If a>0 (assuming positive effective strike): // Payoff = VanillaFloatingLeg + Put(a*rate+b,strike) // --> If a<0 (assuming positive effective strike): // Payoff = VanillaFloatingLeg + Nom * Max(strike-b+|a|*rate+,0) * accrualperiod = // = VanillaFloatingLeg - Call(|a|*rate+b,strike) // // Positive gearing List <CashFlow> flooredLeg_p1 = vars.makeYoYCapFlooredLeg(whichPricer, vars.startDate, vars.length, caps0, floors, vars.volatility, gearing_p, spread_p); Swap floorLeg_p1 = new Swap(fixedLeg, flooredLeg_p1); floorLeg_p1.setPricingEngine(engine); YoYInflationFloor floor_p1 = new YoYInflationFloor(floatLeg_p, new List <double>() { floorstrike }); floor_p1.setPricingEngine(vars.makeEngine(vars.volatility, whichPricer)); npvVanilla = vanillaLeg_p.NPV(); npvFlooredLeg = floorLeg_p1.NPV(); npvFloor = floor_p1.NPV(); error = Math.Abs(npvFlooredLeg - (npvVanilla + npvFloor)); if (error > tolerance) { QAssert.Fail("\nYoY Floored Leg: gearing=" + gearing_p + ", " + "spread= " + spread_p * 100 + "%, strike=" + floorstrike * 100 + "%, " + "effective strike= " + (floorstrike - spread_p) / gearing_p * 100 + "%\n" + " Floored Floating Leg NPV: " + npvFlooredLeg + "\n" + " Floating Leg NPV + Floor NPV: " + (npvVanilla + npvFloor) + "\n" + " Diff: " + error); } // Negative gearing List <CashFlow> flooredLeg_n = vars.makeYoYCapFlooredLeg(whichPricer, vars.startDate, vars.length, caps0, floors, vars.volatility, gearing_n, spread_n); Swap floorLeg_n = new Swap(fixedLeg, flooredLeg_n); floorLeg_n.setPricingEngine(engine); YoYInflationCap cap_n = new YoYInflationCap(floatLeg, new List <double>() { (floorstrike - spread_n) / gearing_n }); cap_n.setPricingEngine(vars.makeEngine(vars.volatility, whichPricer)); npvVanilla = vanillaLeg_n.NPV(); npvFlooredLeg = floorLeg_n.NPV(); npvCap = cap_n.NPV(); error = Math.Abs(npvFlooredLeg - (npvVanilla - gearing_n * npvCap)); if (error > tolerance) { QAssert.Fail("\nYoY Capped Leg: gearing=" + gearing_n + ", " + "spread= " + spread_n * 100 + "%, strike=" + floorstrike * 100 + "%, " + "effective strike= " + (floorstrike - spread_n) / gearing_n * 100 + "%\n" + " Capped Floating Leg NPV: " + npvFlooredLeg + "\n" + " Floating Leg NPV - Cap NPV: " + (npvVanilla - gearing_n * npvCap) + "\n" + " Diff: " + error); } // gearing = a and spread = b // COLLARED coupon - Decomposition of payoff // Payoff = Nom * Min(caprate,Max(a*rate+b,floorrate)) * accrualperiod // --> If a>0 (assuming positive effective strike): // Payoff = VanillaFloatingLeg - Collar(a*rate+b, floorrate, caprate) // --> If a<0 (assuming positive effective strike): // Payoff = VanillaFloatingLeg + Collar(|a|*rate+b, caprate, floorrate) // // Positive gearing List <CashFlow> collaredLeg_p = vars.makeYoYCapFlooredLeg(whichPricer, vars.startDate, vars.length, caps, floors, vars.volatility, gearing_p, spread_p); Swap collarLeg_p1 = new Swap(fixedLeg, collaredLeg_p); collarLeg_p1.setPricingEngine(engine); YoYInflationCollar collar_p = new YoYInflationCollar(floatLeg_p, new List <double>() { capstrike }, new List <double>() { floorstrike }); collar_p.setPricingEngine(vars.makeEngine(vars.volatility, whichPricer)); npvVanilla = vanillaLeg_p.NPV(); npvCollaredLeg = collarLeg_p1.NPV(); npvCollar = collar_p.NPV(); error = Math.Abs(npvCollaredLeg - (npvVanilla - npvCollar)); if (error > tolerance) { QAssert.Fail("\nYoY Collared Leg: gearing=" + gearing_p + ", " + "spread= " + spread_p * 100 + "%, strike=" + floorstrike * 100 + "% and " + capstrike * 100 + "%, " + "effective strike=" + (floorstrike - spread_p) / gearing_p * 100 + "% and " + (capstrike - spread_p) / gearing_p * 100 + "%\n" + " Collared Floating Leg NPV: " + npvCollaredLeg + "\n" + " Floating Leg NPV - Collar NPV: " + (npvVanilla - npvCollar) + "\n" + " Diff: " + error); } // Negative gearing List <CashFlow> collaredLeg_n = vars.makeYoYCapFlooredLeg(whichPricer, vars.startDate, vars.length, caps, floors, vars.volatility, gearing_n, spread_n); Swap collarLeg_n1 = new Swap(fixedLeg, collaredLeg_n); collarLeg_n1.setPricingEngine(engine); YoYInflationCollar collar_n = new YoYInflationCollar(floatLeg, new List <double>() { (floorstrike - spread_n) / gearing_n }, new List <double>() { (capstrike - spread_n) / gearing_n }); collar_n.setPricingEngine(vars.makeEngine(vars.volatility, whichPricer)); npvVanilla = vanillaLeg_n.NPV(); npvCollaredLeg = collarLeg_n1.NPV(); npvCollar = collar_n.NPV(); error = Math.Abs(npvCollaredLeg - (npvVanilla - gearing_n * npvCollar)); if (error > tolerance) { QAssert.Fail("\nYoY Collared Leg: gearing=" + gearing_n + ", " + "spread= " + spread_n * 100 + "%, strike=" + floorstrike * 100 + "% and " + capstrike * 100 + "%, " + "effective strike=" + (floorstrike - spread_n) / gearing_n * 100 + "% and " + (capstrike - spread_n) / gearing_n * 100 + "%\n" + " Collared Floating Leg NPV: " + npvCollaredLeg + "\n" + " Floating Leg NPV - Collar NPV: " + (npvVanilla - gearing_n * npvCollar) + "\n" + " Diff: " + error); } // remove circular refernce vars.hy.linkTo(null); }
void checkSequence <S>(string name, int dimension) where S : IGeneralStatistics, new () { GenericSequenceStatistics <S> ss = new GenericSequenceStatistics <S>(dimension); int i; for (i = 0; i < data.Length; i++) { List <double> temp = new InitializedList <double>(dimension, data[i]); ss.add(temp, weights[i]); } List <double> calculated; double expected, tolerance; if (ss.samples() != data.Length) { QAssert.Fail("SequenceStatistics<" + name + ">: " + "wrong number of samples\n" + " calculated: " + ss.samples() + "\n" + " expected: " + data.Length); } expected = weights.Sum(); if (ss.weightSum() != expected) { QAssert.Fail("SequenceStatistics<" + name + ">: " + "wrong sum of weights\n" + " calculated: " + ss.weightSum() + "\n" + " expected: " + expected); } expected = data.Min(); calculated = ss.min(); for (i = 0; i < dimension; i++) { if (calculated[i] != expected) { QAssert.Fail("SequenceStatistics<" + name + ">: " + (i + 1) + " dimension: " + "wrong minimum value\n" + " calculated: " + calculated[i] + "\n" + " expected: " + expected); } } expected = data.Max(); calculated = ss.max(); for (i = 0; i < dimension; i++) { if (calculated[i] != expected) { QAssert.Fail("SequenceStatistics<" + name + ">: " + (i + 1) + " dimension: " + "wrong maximun value\n" + " calculated: " + calculated[i] + "\n" + " expected: " + expected); } } expected = 4.3; tolerance = 1.0e-9; calculated = ss.mean(); for (i = 0; i < dimension; i++) { if (Math.Abs(calculated[i] - expected) > tolerance) { QAssert.Fail("SequenceStatistics<" + name + ">: " + (i + 1) + " dimension: " + "wrong mean value\n" + " calculated: " + calculated[i] + "\n" + " expected: " + expected); } } expected = 2.23333333333; calculated = ss.variance(); for (i = 0; i < dimension; i++) { if (Math.Abs(calculated[i] - expected) > tolerance) { QAssert.Fail("SequenceStatistics<" + name + ">: " + (i + 1) + " dimension: " + "wrong variance\n" + " calculated: " + calculated[i] + "\n" + " expected: " + expected); } } expected = 1.4944341181; calculated = ss.standardDeviation(); for (i = 0; i < dimension; i++) { if (Math.Abs(calculated[i] - expected) > tolerance) { QAssert.Fail("SequenceStatistics<" + name + ">: " + (i + 1) + " dimension: " + "wrong standard deviation\n" + " calculated: " + calculated[i] + "\n" + " expected: " + expected); } } expected = 0.359543071407; calculated = ss.skewness(); for (i = 0; i < dimension; i++) { if (Math.Abs(calculated[i] - expected) > tolerance) { QAssert.Fail("SequenceStatistics<" + name + ">: " + (i + 1) + " dimension: " + "wrong skewness\n" + " calculated: " + calculated[i] + "\n" + " expected: " + expected); } } expected = -0.151799637209; calculated = ss.kurtosis(); for (i = 0; i < dimension; i++) { if (Math.Abs(calculated[i] - expected) > tolerance) { QAssert.Fail("SequenceStatistics<" + name + ">: " + (i + 1) + " dimension: " + "wrong kurtosis\n" + " calculated: " + calculated[i] + "\n" + " expected: " + expected); } } }
public void testCalibration() { double forward = 0.03; double tau = 1.0; //Real a = 0.04; //Real b = 0.1; //Real rho = -0.5; //Real sigma = 0.1; //Real m = 0.0; double a = 0.1; double b = 0.06; double rho = -0.9; double m = 0.24; double sigma = 0.06; List <double> strikes = new List <double>(); strikes.Add(0.01); strikes.Add(0.015); strikes.Add(0.02); strikes.Add(0.025); strikes.Add(0.03); strikes.Add(0.035); strikes.Add(0.04); strikes.Add(0.045); strikes.Add(0.05); List <double> vols = new InitializedList <double>(strikes.Count, 0.20); //dummy vols (we do not calibrate here) SviInterpolation svi = new SviInterpolation(strikes, strikes.Count, vols, tau, forward, a, b, sigma, rho, m, true, true, true, true, true); svi.enableExtrapolation(); List <double> sviVols = new InitializedList <double>(strikes.Count, 0.0); for (int i = 0; i < strikes.Count; ++i) { sviVols[i] = svi.value(strikes[i]); } SviInterpolation svi2 = new SviInterpolation(strikes, strikes.Count, sviVols, tau, forward, null, null, null, null, null, false, false, false, false, false, false, null, null, 1E-8, false, 0); //don't allow for random start values svi2.enableExtrapolation(); svi2.update(); Console.WriteLine("a=" + svi2.a()); if (!Utils.close_enough(a, svi2.a(), 100)) { QAssert.Fail("error in a coefficient estimation"); } Console.WriteLine("b=" + svi2.b()); if (!Utils.close_enough(b, svi2.b(), 100)) { QAssert.Fail("error in b coefficient estimation"); } Console.WriteLine("sigma=" + svi2.sigma()); if (!Utils.close_enough(sigma, svi2.sigma(), 100)) { QAssert.Fail("error in sigma coefficient estimation"); } Console.WriteLine("rho=" + svi2.rho()); if (!Utils.close_enough(rho, svi2.rho(), 100)) { QAssert.Fail("error in rho coefficient estimation"); } Console.WriteLine("m=" + svi2.m()); if (!Utils.close_enough(m, svi2.m(), 100)) { QAssert.Fail("error in m coefficient estimation"); } Console.WriteLine("error=" + svi2.rmsError()); }
public void testDecomposition() { // Testing collared coupon against its decomposition CommonVars vars = new CommonVars(); double tolerance = 1e-12; double npvVanilla, npvCappedLeg, npvFlooredLeg, npvCollaredLeg, npvCap, npvFloor, npvCollar; double error; double floorstrike = 0.05; double capstrike = 0.10; List <double?> caps = new InitializedList <double?>(vars.length, capstrike); List <double?> caps0 = new List <double?>(); List <double?> floors = new InitializedList <double?>(vars.length, floorstrike); List <double?> floors0 = new List <double?>(); double gearing_p = 0.5; double spread_p = 0.002; double gearing_n = -1.5; double spread_n = 0.12; // fixed leg with zero rate List <CashFlow> fixedLeg = vars.makeFixedLeg(vars.startDate, vars.length); // floating leg with gearing=1 and spread=0 List <CashFlow> floatLeg = vars.makeFloatingLeg(vars.startDate, vars.length); // floating leg with positive gearing (gearing_p) and spread<>0 List <CashFlow> floatLeg_p = vars.makeFloatingLeg(vars.startDate, vars.length, gearing_p, spread_p); // floating leg with negative gearing (gearing_n) and spread<>0 List <CashFlow> floatLeg_n = vars.makeFloatingLeg(vars.startDate, vars.length, gearing_n, spread_n); // Swap with null fixed leg and floating leg with gearing=1 and spread=0 Swap vanillaLeg = new Swap(fixedLeg, floatLeg); // Swap with null fixed leg and floating leg with positive gearing and spread<>0 Swap vanillaLeg_p = new Swap(fixedLeg, floatLeg_p); // Swap with null fixed leg and floating leg with negative gearing and spread<>0 Swap vanillaLeg_n = new Swap(fixedLeg, floatLeg_n); IPricingEngine engine = new DiscountingSwapEngine(vars.termStructure); vanillaLeg.setPricingEngine(engine); vanillaLeg_p.setPricingEngine(engine); vanillaLeg_n.setPricingEngine(engine); /* CAPPED coupon - Decomposition of payoff * Payoff = Nom * Min(rate,strike) * accrualperiod = * = Nom * [rate + Min(0,strike-rate)] * accrualperiod = * = Nom * rate * accrualperiod - Nom * Max(rate-strike,0) * accrualperiod = * = VanillaFloatingLeg - Call */ // Case gearing = 1 and spread = 0 List <CashFlow> cappedLeg = vars.makeCapFlooredLeg(vars.startDate, vars.length, caps, floors0, vars.volatility); Swap capLeg = new Swap(fixedLeg, cappedLeg); capLeg.setPricingEngine(engine); Cap cap = new Cap(floatLeg, new InitializedList <double>(1, capstrike)); cap.setPricingEngine(vars.makeEngine(vars.volatility)); npvVanilla = vanillaLeg.NPV(); npvCappedLeg = capLeg.NPV(); npvCap = cap.NPV(); error = Math.Abs(npvCappedLeg - (npvVanilla - npvCap)); if (error > tolerance) { QAssert.Fail("\nCapped Leg: gearing=1, spread=0%, strike=" + capstrike * 100 + "%\n" + " Capped Floating Leg NPV: " + npvCappedLeg + "\n" + " Floating Leg NPV - Cap NPV: " + (npvVanilla - npvCap) + "\n" + " Diff: " + error); } /* gearing = 1 and spread = 0 * FLOORED coupon - Decomposition of payoff * Payoff = Nom * Max(rate,strike) * accrualperiod = * = Nom * [rate + Max(0,strike-rate)] * accrualperiod = * = Nom * rate * accrualperiod + Nom * Max(strike-rate,0) * accrualperiod = * = VanillaFloatingLeg + Put */ List <CashFlow> flooredLeg = vars.makeCapFlooredLeg(vars.startDate, vars.length, caps0, floors, vars.volatility); Swap floorLeg = new Swap(fixedLeg, flooredLeg); floorLeg.setPricingEngine(engine); Floor floor = new Floor(floatLeg, new InitializedList <double>(1, floorstrike)); floor.setPricingEngine(vars.makeEngine(vars.volatility)); npvFlooredLeg = floorLeg.NPV(); npvFloor = floor.NPV(); error = Math.Abs(npvFlooredLeg - (npvVanilla + npvFloor)); if (error > tolerance) { QAssert.Fail("Floored Leg: gearing=1, spread=0%, strike=" + floorstrike * 100 + "%\n" + " Floored Floating Leg NPV: " + npvFlooredLeg + "\n" + " Floating Leg NPV + Floor NPV: " + (npvVanilla + npvFloor) + "\n" + " Diff: " + error); } /* gearing = 1 and spread = 0 * COLLARED coupon - Decomposition of payoff * Payoff = Nom * Min(strikem,Max(rate,strikeM)) * accrualperiod = * = VanillaFloatingLeg - Collar */ List <CashFlow> collaredLeg = vars.makeCapFlooredLeg(vars.startDate, vars.length, caps, floors, vars.volatility); Swap collarLeg = new Swap(fixedLeg, collaredLeg); collarLeg.setPricingEngine(engine); Collar collar = new Collar(floatLeg, new InitializedList <double>(1, capstrike), new InitializedList <double>(1, floorstrike)); collar.setPricingEngine(vars.makeEngine(vars.volatility)); npvCollaredLeg = collarLeg.NPV(); npvCollar = collar.NPV(); error = Math.Abs(npvCollaredLeg - (npvVanilla - npvCollar)); if (error > tolerance) { QAssert.Fail("\nCollared Leg: gearing=1, spread=0%, strike=" + floorstrike * 100 + "% and " + capstrike * 100 + "%\n" + " Collared Floating Leg NPV: " + npvCollaredLeg + "\n" + " Floating Leg NPV - Collar NPV: " + (npvVanilla - npvCollar) + "\n" + " Diff: " + error); } /* gearing = a and spread = b * CAPPED coupon - Decomposition of payoff * Payoff * = Nom * Min(a*rate+b,strike) * accrualperiod = * = Nom * [a*rate+b + Min(0,strike-a*rate-b)] * accrualperiod = * = Nom * a*rate+b * accrualperiod + Nom * Min(strike-b-a*rate,0) * accrualperiod * --> If a>0 (assuming positive effective strike): * Payoff = VanillaFloatingLeg - Call(a*rate+b,strike) * --> If a<0 (assuming positive effective strike): * Payoff = VanillaFloatingLeg + Nom * Min(strike-b+|a|*rate+,0) * accrualperiod = * = VanillaFloatingLeg + Put(|a|*rate+b,strike) */ // Positive gearing List <CashFlow> cappedLeg_p = vars.makeCapFlooredLeg(vars.startDate, vars.length, caps, floors0, vars.volatility, gearing_p, spread_p); Swap capLeg_p = new Swap(fixedLeg, cappedLeg_p); capLeg_p.setPricingEngine(engine); Cap cap_p = new Cap(floatLeg_p, new InitializedList <double>(1, capstrike)); cap_p.setPricingEngine(vars.makeEngine(vars.volatility)); npvVanilla = vanillaLeg_p.NPV(); npvCappedLeg = capLeg_p.NPV(); npvCap = cap_p.NPV(); error = Math.Abs(npvCappedLeg - (npvVanilla - npvCap)); if (error > tolerance) { QAssert.Fail("\nCapped Leg: gearing=" + gearing_p + ", " + "spread= " + spread_p * 100 + "%, strike=" + capstrike * 100 + "%, " + "effective strike= " + (capstrike - spread_p) / gearing_p * 100 + "%\n" + " Capped Floating Leg NPV: " + npvCappedLeg + "\n" + " Vanilla Leg NPV: " + npvVanilla + "\n" + " Cap NPV: " + npvCap + "\n" + " Floating Leg NPV - Cap NPV: " + (npvVanilla - npvCap) + "\n" + " Diff: " + error); } // Negative gearing List <CashFlow> cappedLeg_n = vars.makeCapFlooredLeg(vars.startDate, vars.length, caps, floors0, vars.volatility, gearing_n, spread_n); Swap capLeg_n = new Swap(fixedLeg, cappedLeg_n); capLeg_n.setPricingEngine(engine); Floor floor_n = new Floor(floatLeg, new InitializedList <double>(1, (capstrike - spread_n) / gearing_n)); floor_n.setPricingEngine(vars.makeEngine(vars.volatility)); npvVanilla = vanillaLeg_n.NPV(); npvCappedLeg = capLeg_n.NPV(); npvFloor = floor_n.NPV(); error = Math.Abs(npvCappedLeg - (npvVanilla + gearing_n * npvFloor)); if (error > tolerance) { QAssert.Fail("\nCapped Leg: gearing=" + gearing_n + ", " + "spread= " + spread_n * 100 + "%, strike=" + capstrike * 100 + "%, " + "effective strike= " + (capstrike - spread_n) / gearing_n * 100 + "%\n" + " Capped Floating Leg NPV: " + npvCappedLeg + "\n" + " npv Vanilla: " + npvVanilla + "\n" + " npvFloor: " + npvFloor + "\n" + " Floating Leg NPV - Cap NPV: " + (npvVanilla + gearing_n * npvFloor) + "\n" + " Diff: " + error); } /* gearing = a and spread = b * FLOORED coupon - Decomposition of payoff * Payoff * = Nom * Max(a*rate+b,strike) * accrualperiod = * = Nom * [a*rate+b + Max(0,strike-a*rate-b)] * accrualperiod = * = Nom * a*rate+b * accrualperiod + Nom * Max(strike-b-a*rate,0) * accrualperiod * --> If a>0 (assuming positive effective strike): * Payoff = VanillaFloatingLeg + Put(a*rate+b,strike) * --> If a<0 (assuming positive effective strike): * Payoff = VanillaFloatingLeg + Nom * Max(strike-b+|a|*rate+,0) * accrualperiod = * = VanillaFloatingLeg - Call(|a|*rate+b,strike) */ // Positive gearing List <CashFlow> flooredLeg_p1 = vars.makeCapFlooredLeg(vars.startDate, vars.length, caps0, floors, vars.volatility, gearing_p, spread_p); Swap floorLeg_p1 = new Swap(fixedLeg, flooredLeg_p1); floorLeg_p1.setPricingEngine(engine); Floor floor_p1 = new Floor(floatLeg_p, new InitializedList <double>(1, floorstrike)); floor_p1.setPricingEngine(vars.makeEngine(vars.volatility)); npvVanilla = vanillaLeg_p.NPV(); npvFlooredLeg = floorLeg_p1.NPV(); npvFloor = floor_p1.NPV(); error = Math.Abs(npvFlooredLeg - (npvVanilla + npvFloor)); if (error > tolerance) { QAssert.Fail("\nFloored Leg: gearing=" + gearing_p + ", " + "spread= " + spread_p * 100 + "%, strike=" + floorstrike * 100 + "%, " + "effective strike= " + (floorstrike - spread_p) / gearing_p * 100 + "%\n" + " Floored Floating Leg NPV: " + npvFlooredLeg + "\n" + " Floating Leg NPV + Floor NPV: " + (npvVanilla + npvFloor) + "\n" + " Diff: " + error); } // Negative gearing List <CashFlow> flooredLeg_n = vars.makeCapFlooredLeg(vars.startDate, vars.length, caps0, floors, vars.volatility, gearing_n, spread_n); Swap floorLeg_n = new Swap(fixedLeg, flooredLeg_n); floorLeg_n.setPricingEngine(engine); Cap cap_n = new Cap(floatLeg, new InitializedList <double>(1, (floorstrike - spread_n) / gearing_n)); cap_n.setPricingEngine(vars.makeEngine(vars.volatility)); npvVanilla = vanillaLeg_n.NPV(); npvFlooredLeg = floorLeg_n.NPV(); npvCap = cap_n.NPV(); error = Math.Abs(npvFlooredLeg - (npvVanilla - gearing_n * npvCap)); if (error > tolerance) { QAssert.Fail("\nCapped Leg: gearing=" + gearing_n + ", " + "spread= " + spread_n * 100 + "%, strike=" + floorstrike * 100 + "%, " + "effective strike= " + (floorstrike - spread_n) / gearing_n * 100 + "%\n" + " Capped Floating Leg NPV: " + npvFlooredLeg + "\n" + " Floating Leg NPV - Cap NPV: " + (npvVanilla - gearing_n * npvCap) + "\n" + " Diff: " + error); } /* gearing = a and spread = b * COLLARED coupon - Decomposition of payoff * Payoff = Nom * Min(caprate,Max(a*rate+b,floorrate)) * accrualperiod * --> If a>0 (assuming positive effective strike): * Payoff = VanillaFloatingLeg - Collar(a*rate+b, floorrate, caprate) * --> If a<0 (assuming positive effective strike): * Payoff = VanillaFloatingLeg + Collar(|a|*rate+b, caprate, floorrate) */ // Positive gearing List <CashFlow> collaredLeg_p = vars.makeCapFlooredLeg(vars.startDate, vars.length, caps, floors, vars.volatility, gearing_p, spread_p); Swap collarLeg_p1 = new Swap(fixedLeg, collaredLeg_p); collarLeg_p1.setPricingEngine(engine); Collar collar_p = new Collar(floatLeg_p, new InitializedList <double>(1, capstrike), new InitializedList <double>(1, floorstrike)); collar_p.setPricingEngine(vars.makeEngine(vars.volatility)); npvVanilla = vanillaLeg_p.NPV(); npvCollaredLeg = collarLeg_p1.NPV(); npvCollar = collar_p.NPV(); error = Math.Abs(npvCollaredLeg - (npvVanilla - npvCollar)); if (error > tolerance) { QAssert.Fail("\nCollared Leg: gearing=" + gearing_p + ", " + "spread= " + spread_p * 100 + "%, strike=" + floorstrike * 100 + "% and " + capstrike * 100 + "%, " + "effective strike=" + (floorstrike - spread_p) / gearing_p * 100 + "% and " + (capstrike - spread_p) / gearing_p * 100 + "%\n" + " Collared Floating Leg NPV: " + npvCollaredLeg + "\n" + " Floating Leg NPV - Collar NPV: " + (npvVanilla - npvCollar) + "\n" + " Diff: " + error); } // Negative gearing List <CashFlow> collaredLeg_n = vars.makeCapFlooredLeg(vars.startDate, vars.length, caps, floors, vars.volatility, gearing_n, spread_n); Swap collarLeg_n1 = new Swap(fixedLeg, collaredLeg_n); collarLeg_n1.setPricingEngine(engine); Collar collar_n = new Collar(floatLeg, new InitializedList <double>(1, (floorstrike - spread_n) / gearing_n), new InitializedList <double>(1, (capstrike - spread_n) / gearing_n)); collar_n.setPricingEngine(vars.makeEngine(vars.volatility)); npvVanilla = vanillaLeg_n.NPV(); npvCollaredLeg = collarLeg_n1.NPV(); npvCollar = collar_n.NPV(); error = Math.Abs(npvCollaredLeg - (npvVanilla - gearing_n * npvCollar)); if (error > tolerance) { QAssert.Fail("\nCollared Leg: gearing=" + gearing_n + ", " + "spread= " + spread_n * 100 + "%, strike=" + floorstrike * 100 + "% and " + capstrike * 100 + "%, " + "effective strike=" + (floorstrike - spread_n) / gearing_n * 100 + "% and " + (capstrike - spread_n) / gearing_n * 100 + "%\n" + " Collared Floating Leg NPV: " + npvCollaredLeg + "\n" + " Floating Leg NPV - Collar NPV: " + (npvVanilla - gearing_n * npvCollar) + "\n" + " Diff: " + error); } }
// setup public CommonVars() { backup = new SavedSettings(); Calendar calendar = new TARGET(); Date referenceDate = calendar.adjust(Date.Today); Settings.Instance.setEvaluationDate(referenceDate); termStructure = new RelinkableHandle <YieldTermStructure>(); termStructure.linkTo(Utilities.flatRate(referenceDate, 0.05, new Actual365Fixed())); // ATM Volatility structure List <Period> atmOptionTenors = new List <Period>(); atmOptionTenors.Add(new Period(1, TimeUnit.Months)); atmOptionTenors.Add(new Period(6, TimeUnit.Months)); atmOptionTenors.Add(new Period(1, TimeUnit.Years)); atmOptionTenors.Add(new Period(5, TimeUnit.Years)); atmOptionTenors.Add(new Period(10, TimeUnit.Years)); atmOptionTenors.Add(new Period(30, TimeUnit.Years)); List <Period> atmSwapTenors = new List <Period>(); atmSwapTenors.Add(new Period(1, TimeUnit.Years)); atmSwapTenors.Add(new Period(5, TimeUnit.Years)); atmSwapTenors.Add(new Period(10, TimeUnit.Years)); atmSwapTenors.Add(new Period(30, TimeUnit.Years)); Matrix m = new Matrix(atmOptionTenors.Count, atmSwapTenors.Count); m[0, 0] = 0.1300; m[0, 1] = 0.1560; m[0, 2] = 0.1390; m[0, 3] = 0.1220; m[1, 0] = 0.1440; m[1, 1] = 0.1580; m[1, 2] = 0.1460; m[1, 3] = 0.1260; m[2, 0] = 0.1600; m[2, 1] = 0.1590; m[2, 2] = 0.1470; m[2, 3] = 0.1290; m[3, 0] = 0.1640; m[3, 1] = 0.1470; m[3, 2] = 0.1370; m[3, 3] = 0.1220; m[4, 0] = 0.1400; m[4, 1] = 0.1300; m[4, 2] = 0.1250; m[4, 3] = 0.1100; m[5, 0] = 0.1130; m[5, 1] = 0.1090; m[5, 2] = 0.1070; m[5, 3] = 0.0930; atmVol = new Handle <SwaptionVolatilityStructure>( new SwaptionVolatilityMatrix(calendar, BusinessDayConvention.Following, atmOptionTenors, atmSwapTenors, m, new Actual365Fixed())); // Vol cubes List <Period> optionTenors = new List <Period>(); optionTenors.Add(new Period(1, TimeUnit.Years)); optionTenors.Add(new Period(10, TimeUnit.Years)); optionTenors.Add(new Period(30, TimeUnit.Years)); List <Period> swapTenors = new List <Period>(); swapTenors.Add(new Period(2, TimeUnit.Years)); swapTenors.Add(new Period(10, TimeUnit.Years)); swapTenors.Add(new Period(30, TimeUnit.Years)); List <double> strikeSpreads = new List <double>(); strikeSpreads.Add(-0.020); strikeSpreads.Add(-0.005); strikeSpreads.Add(+0.000); strikeSpreads.Add(+0.005); strikeSpreads.Add(+0.020); int nRows = optionTenors.Count * swapTenors.Count; int nCols = strikeSpreads.Count; Matrix volSpreadsMatrix = new Matrix(nRows, nCols); volSpreadsMatrix[0, 0] = 0.0599; volSpreadsMatrix[0, 1] = 0.0049; volSpreadsMatrix[0, 2] = 0.0000; volSpreadsMatrix[0, 3] = -0.0001; volSpreadsMatrix[0, 4] = 0.0127; volSpreadsMatrix[1, 0] = 0.0729; volSpreadsMatrix[1, 1] = 0.0086; volSpreadsMatrix[1, 2] = 0.0000; volSpreadsMatrix[1, 3] = -0.0024; volSpreadsMatrix[1, 4] = 0.0098; volSpreadsMatrix[2, 0] = 0.0738; volSpreadsMatrix[2, 1] = 0.0102; volSpreadsMatrix[2, 2] = 0.0000; volSpreadsMatrix[2, 3] = -0.0039; volSpreadsMatrix[2, 4] = 0.0065; volSpreadsMatrix[3, 0] = 0.0465; volSpreadsMatrix[3, 1] = 0.0063; volSpreadsMatrix[3, 2] = 0.0000; volSpreadsMatrix[3, 3] = -0.0032; volSpreadsMatrix[3, 4] = -0.0010; volSpreadsMatrix[4, 0] = 0.0558; volSpreadsMatrix[4, 1] = 0.0084; volSpreadsMatrix[4, 2] = 0.0000; volSpreadsMatrix[4, 3] = -0.0050; volSpreadsMatrix[4, 4] = -0.0057; volSpreadsMatrix[5, 0] = 0.0576; volSpreadsMatrix[5, 1] = 0.0083; volSpreadsMatrix[5, 2] = 0.0000; volSpreadsMatrix[5, 3] = -0.0043; volSpreadsMatrix[5, 4] = -0.0014; volSpreadsMatrix[6, 0] = 0.0437; volSpreadsMatrix[6, 1] = 0.0059; volSpreadsMatrix[6, 2] = 0.0000; volSpreadsMatrix[6, 3] = -0.0030; volSpreadsMatrix[6, 4] = -0.0006; volSpreadsMatrix[7, 0] = 0.0533; volSpreadsMatrix[7, 1] = 0.0078; volSpreadsMatrix[7, 2] = 0.0000; volSpreadsMatrix[7, 3] = -0.0045; volSpreadsMatrix[7, 4] = -0.0046; volSpreadsMatrix[8, 0] = 0.0545; volSpreadsMatrix[8, 1] = 0.0079; volSpreadsMatrix[8, 2] = 0.0000; volSpreadsMatrix[8, 3] = -0.0042; volSpreadsMatrix[8, 4] = -0.0020; List <List <Handle <Quote> > > volSpreads = new InitializedList <List <Handle <Quote> > >(nRows); for (int i = 0; i < nRows; ++i) { volSpreads[i] = new InitializedList <Handle <Quote> >(nCols); for (int j = 0; j < nCols; ++j) { volSpreads[i][j] = new Handle <Quote>(new SimpleQuote(volSpreadsMatrix[i, j])); } } iborIndex = new Euribor6M(termStructure); SwapIndex swapIndexBase = new EuriborSwapIsdaFixA(new Period(10, TimeUnit.Years), termStructure); SwapIndex shortSwapIndexBase = new EuriborSwapIsdaFixA(new Period(2, TimeUnit.Years), termStructure); bool vegaWeightedSmileFit = false; SabrVolCube2 = new Handle <SwaptionVolatilityStructure>( new SwaptionVolCube2(atmVol, optionTenors, swapTenors, strikeSpreads, volSpreads, swapIndexBase, shortSwapIndexBase, vegaWeightedSmileFit)); SabrVolCube2.link.enableExtrapolation(); List <List <Handle <Quote> > > guess = new InitializedList <List <Handle <Quote> > >(nRows); for (int i = 0; i < nRows; ++i) { guess[i] = new InitializedList <Handle <Quote> >(4); guess[i][0] = new Handle <Quote>(new SimpleQuote(0.2)); guess[i][1] = new Handle <Quote>(new SimpleQuote(0.5)); guess[i][2] = new Handle <Quote>(new SimpleQuote(0.4)); guess[i][3] = new Handle <Quote>(new SimpleQuote(0.0)); } List <bool> isParameterFixed = new InitializedList <bool>(4, false); isParameterFixed[1] = true; // FIXME bool isAtmCalibrated = false; SabrVolCube1 = new Handle <SwaptionVolatilityStructure>( new SwaptionVolCube1x(atmVol, optionTenors, swapTenors, strikeSpreads, volSpreads, swapIndexBase, shortSwapIndexBase, vegaWeightedSmileFit, guess, isParameterFixed, isAtmCalibrated)); SabrVolCube1.link.enableExtrapolation(); yieldCurveModels = new List <GFunctionFactory.YieldCurveModel>(); yieldCurveModels.Add(GFunctionFactory.YieldCurveModel.Standard); yieldCurveModels.Add(GFunctionFactory.YieldCurveModel.ExactYield); yieldCurveModels.Add(GFunctionFactory.YieldCurveModel.ParallelShifts); yieldCurveModels.Add(GFunctionFactory.YieldCurveModel.NonParallelShifts); yieldCurveModels.Add(GFunctionFactory.YieldCurveModel.NonParallelShifts); // for linear tsr model Handle <Quote> zeroMeanRev = new Handle <Quote>(new SimpleQuote(0.0)); numericalPricers = new List <CmsCouponPricer>(); analyticPricers = new List <CmsCouponPricer>(); for (int j = 0; j < yieldCurveModels.Count; ++j) { if (j < yieldCurveModels.Count - 1) { numericalPricers.Add(new NumericHaganPricer(atmVol, yieldCurveModels[j], zeroMeanRev)); } else { numericalPricers.Add(new LinearTsrPricer(atmVol, zeroMeanRev)); } analyticPricers.Add(new AnalyticHaganPricer(atmVol, yieldCurveModels[j], zeroMeanRev)); } }
public void testCrankNicolsonWithDamping() { SavedSettings backup = new SavedSettings(); DayCounter dc = new Actual360(); Date today = Date.Today; SimpleQuote spot = new SimpleQuote(100.0); YieldTermStructure qTS = Utilities.flatRate(today, 0.06, dc); YieldTermStructure rTS = Utilities.flatRate(today, 0.06, dc); BlackVolTermStructure volTS = Utilities.flatVol(today, 0.35, dc); StrikedTypePayoff payoff = new CashOrNothingPayoff(Option.Type.Put, 100, 10.0); double maturity = 0.75; Date exDate = today + Convert.ToInt32(maturity * 360 + 0.5); Exercise exercise = new EuropeanExercise(exDate); BlackScholesMertonProcess process = new BlackScholesMertonProcess(new Handle <Quote>(spot), new Handle <YieldTermStructure>(qTS), new Handle <YieldTermStructure>(rTS), new Handle <BlackVolTermStructure>(volTS)); IPricingEngine engine = new AnalyticEuropeanEngine(process); VanillaOption opt = new VanillaOption(payoff, exercise); opt.setPricingEngine(engine); double expectedPV = opt.NPV(); double expectedGamma = opt.gamma(); // fd pricing using implicit damping steps and Crank Nicolson int csSteps = 25, dampingSteps = 3, xGrid = 400; List <int> dim = new InitializedList <int>(1, xGrid); FdmLinearOpLayout layout = new FdmLinearOpLayout(dim); Fdm1dMesher equityMesher = new FdmBlackScholesMesher( dim[0], process, maturity, payoff.strike(), null, null, 0.0001, 1.5, new Pair <double?, double?>(payoff.strike(), 0.01)); FdmMesher mesher = new FdmMesherComposite(equityMesher); FdmBlackScholesOp map = new FdmBlackScholesOp(mesher, process, payoff.strike()); FdmInnerValueCalculator calculator = new FdmLogInnerValue(payoff, mesher, 0); object rhs = new Vector(layout.size()); Vector x = new Vector(layout.size()); FdmLinearOpIterator endIter = layout.end(); for (FdmLinearOpIterator iter = layout.begin(); iter != endIter; ++iter) { (rhs as Vector)[iter.index()] = calculator.avgInnerValue(iter, maturity); x[iter.index()] = mesher.location(iter, 0); } FdmBackwardSolver solver = new FdmBackwardSolver(map, new FdmBoundaryConditionSet(), new FdmStepConditionComposite(), new FdmSchemeDesc().Douglas()); solver.rollback(ref rhs, maturity, 0.0, csSteps, dampingSteps); MonotonicCubicNaturalSpline spline = new MonotonicCubicNaturalSpline(x, x.Count, rhs as Vector); double s = spot.value(); double calculatedPV = spline.value(Math.Log(s)); double calculatedGamma = (spline.secondDerivative(Math.Log(s)) - spline.derivative(Math.Log(s))) / (s * s); double relTol = 2e-3; if (Math.Abs(calculatedPV - expectedPV) > relTol * expectedPV) { QAssert.Fail("Error calculating the PV of the digital option" + "\n rel. tolerance: " + relTol + "\n expected: " + expectedPV + "\n calculated: " + calculatedPV); } if (Math.Abs(calculatedGamma - expectedGamma) > relTol * expectedGamma) { QAssert.Fail("Error calculating the Gamma of the digital option" + "\n rel. tolerance: " + relTol + "\n expected: " + expectedGamma + "\n calculated: " + calculatedGamma); } }
public void testStrikeDependency() { //("Testing swaption dependency on strike......"); CommonVars vars = new CommonVars(); double[] strikes = new double[] { 0.03, 0.04, 0.05, 0.06, 0.07 }; for (int i = 0; i < exercises.Length; i++) { for (int j = 0; j < lengths.Length; j++) { for (int k = 0; k < type.Length; k++) { Date exerciseDate = vars.calendar.advance(vars.today, exercises[i]); Date startDate = vars.calendar.advance(exerciseDate, vars.settlementDays, TimeUnit.Days); // store the results for different rates... List <double> values = new InitializedList <double>(strikes.Length); List <double> values_cash = new InitializedList <double>(strikes.Length); double vol = 0.20; for (int l = 0; l < strikes.Length; l++) { VanillaSwap swap = new MakeVanillaSwap(lengths[j], vars.index, strikes[l]) .withEffectiveDate(startDate) .withFloatingLegSpread(0.0) .withType(type[k]); Swaption swaption = vars.makeSwaption(swap, exerciseDate, vol); // FLOATING_POINT_EXCEPTION values[l] = swaption.NPV(); Swaption swaption_cash = vars.makeSwaption(swap, exerciseDate, vol, Settlement.Type.Cash); values_cash[l] = swaption_cash.NPV(); } // and check that they go the right way if (type[k] == VanillaSwap.Type.Payer) { for (int z = 0; z < values.Count - 1; z++) { if (values[z] < values[z + 1]) { Assert.Fail("NPV of Payer swaption with delivery settlement" + "is increasing with the strike:" + "\noption tenor: " + exercises[i] + "\noption date: " + exerciseDate + "\nvolatility: " + vol + "\nswap tenor: " + lengths[j] + "\nvalue: " + values[z] + " at strike: " + strikes[z] + "\nvalue: " + values[z + 1] + " at strike: " + strikes[z + 1]); } } for (int z = 0; z < values_cash.Count - 1; z++) { if (values_cash[z] < values_cash[z + 1]) { Assert.Fail("NPV of Payer swaption with cash settlement" + "is increasing with the strike:" + "\noption tenor: " + exercises[i] + "\noption date: " + exerciseDate + "\nvolatility: " + vol + "\nswap tenor: " + lengths[j] + "\nvalue: " + values_cash[z] + " at strike: " + strikes[z] + "\nvalue: " + values_cash[z + 1] + " at strike: " + strikes[z + 1]); } } } else { for (int z = 0; z < values.Count - 1; z++) { if (values[z] > values[z + 1]) { Assert.Fail("NPV of Receiver swaption with delivery settlement" + "is increasing with the strike:" + "\noption tenor: " + exercises[i] + "\noption date: " + exerciseDate + "\nvolatility: " + vol + "\nswap tenor: " + lengths[j] + "\nvalue: " + values[z] + " at strike: " + strikes[z] + "\nvalue: " + values[z + 1] + " at strike: " + strikes[z + 1]); } } for (int z = 0; z < values_cash.Count - 1; z++) { if (values[z] > values[z + 1]) { Assert.Fail("NPV of Receiver swaption with cash settlement" + "is increasing with the strike:" + "\noption tenor: " + exercises[i] + "\noption date: " + exerciseDate + "\nvolatility: " + vol + "\nswap tenor: " + lengths[j] + "\nvalue: " + values_cash[z] + " at strike: " + strikes[z] + "\nvalue: " + values_cash[z + 1] + " at strike: " + strikes[z + 1]); } } } } } } }
public CubicInterpolationImpl(List<double> xBegin, int size, List<double> yBegin, CubicInterpolation.DerivativeApprox da, bool monotonic, CubicInterpolation.BoundaryCondition leftCondition, double leftConditionValue, CubicInterpolation.BoundaryCondition rightCondition, double rightConditionValue) : base(xBegin, size, yBegin) { da_ = da; monotonic_ = monotonic; leftType_ = leftCondition; rightType_ = rightCondition; leftValue_ = leftConditionValue; rightValue_ = rightConditionValue; // coefficients primitiveConst_ = new InitializedList<double>(size - 1); a_ = new InitializedList<double>(size - 1); b_ = new InitializedList<double>(size - 1); c_ = new InitializedList<double>(size - 1); monotonicityAdjustments_ = new InitializedList<bool>(size); }
public double value(Vector p, List<CalibrationHelper> instruments) { List<double> w = new InitializedList<double>(instruments.Count, 1.0); CalibrationFunction f = new CalibrationFunction(this, instruments, w); return f.value(p); }
public List <CashFlow> makeYoYCapFlooredLeg(int which, Date startDate, int length, List <double> caps, List <double> floors, double volatility, double gearing = 1.0, double spread = 0.0) { Handle <YoYOptionletVolatilitySurface> vol = new Handle <YoYOptionletVolatilitySurface>( new ConstantYoYOptionletVolatility(volatility, settlementDays, calendar, convention, dc, observationLag, frequency, iir.interpolated())); YoYInflationCouponPricer pricer = null; switch (which) { case 0: pricer = new BlackYoYInflationCouponPricer(vol); break; case 1: pricer = new UnitDisplacedBlackYoYInflationCouponPricer(vol); break; case 2: pricer = new BachelierYoYInflationCouponPricer(vol); break; default: QAssert.Fail("unknown coupon pricer request: which = " + which + "should be 0=Black,1=DD,2=Bachelier"); break; } List <double> gearingVector = new InitializedList <double>(length, gearing); List <double> spreadVector = new InitializedList <double>(length, spread); YoYInflationIndex ii = iir as YoYInflationIndex; Date endDate = calendar.advance(startDate, new Period(length, TimeUnit.Years), BusinessDayConvention.Unadjusted); Schedule schedule = new Schedule(startDate, endDate, new Period(frequency), calendar, BusinessDayConvention.Unadjusted, BusinessDayConvention.Unadjusted,// ref periods & acc periods DateGeneration.Rule.Forward, false); List <CashFlow> yoyLeg = new yoyInflationLeg(schedule, calendar, ii, observationLag) .withPaymentDayCounter(dc) .withGearings(gearingVector) .withSpreads(spreadVector) .withCaps(caps) .withFloors(floors) .withNotionals(nominals) .withPaymentAdjustment(convention); for (int i = 0; i < yoyLeg.Count; i++) { ((YoYInflationCoupon)(yoyLeg[i])).setPricer(pricer); } //setCouponPricer(iborLeg, pricer); return(yoyLeg); }
public void testBrazilianCached() { //("Testing Brazilian public bond prices against cached values..."); CommonVars vars = new CommonVars(); double faceAmount = 1000.0; double redemption = 100.0; Date issueDate = new Date(1, Month.January, 2007); Date today = new Date(6, Month.June, 2007); Settings.setEvaluationDate(today); // NTN-F maturity dates InitializedList <Date> maturityDates = new InitializedList <Date>(6); maturityDates[0] = new Date(1, Month.January, 2008); maturityDates[1] = new Date(1, Month.January, 2010); maturityDates[2] = new Date(1, Month.July, 2010); maturityDates[3] = new Date(1, Month.January, 2012); maturityDates[4] = new Date(1, Month.January, 2014); maturityDates[5] = new Date(1, Month.January, 2017); // NTN-F yields InitializedList <double> yields = new InitializedList <double>(6); yields[0] = 0.114614; yields[1] = 0.105726; yields[2] = 0.105328; yields[3] = 0.104283; yields[4] = 0.103218; yields[5] = 0.102948; // NTN-F prices InitializedList <double> prices = new InitializedList <double>(6); prices[0] = 1034.63031372; prices[1] = 1030.09919487; prices[2] = 1029.98307160; prices[3] = 1028.13585068; prices[4] = 1028.33383817; prices[5] = 1026.19716497; int settlementDays = 1; vars.faceAmount = 1000.0; // The tolerance is high because Andima truncate yields double tolerance = 1.0e-4; InitializedList <InterestRate> couponRates = new InitializedList <InterestRate>(1); couponRates[0] = new InterestRate(0.1, new Thirty360(), Compounding.Compounded, Frequency.Annual); for (int bondIndex = 0; bondIndex < maturityDates.Count; bondIndex++) { // plain InterestRate yield = new InterestRate(yields[bondIndex], new Business252(new Brazil()), Compounding.Compounded, Frequency.Annual); Schedule schedule = new Schedule(new Date(1, Month.January, 2007), maturityDates[bondIndex], new Period(Frequency.Semiannual), new Brazil(Brazil.Market.Settlement), BusinessDayConvention.Unadjusted, BusinessDayConvention.Unadjusted, DateGeneration.Rule.Backward, false); FixedRateBond bond = new FixedRateBond(settlementDays, faceAmount, schedule, couponRates, BusinessDayConvention.Following, redemption, issueDate); double cachedPrice = prices[bondIndex]; double price = vars.faceAmount * (bond.cleanPrice(yield.rate(), yield.dayCounter(), yield.compounding(), yield.frequency(), today) + bond.accruedAmount(today)) / 100; if (Math.Abs(price - cachedPrice) > tolerance) { Assert.Fail("failed to reproduce cached price:\n" + " calculated: " + price + "\n" + " expected: " + cachedPrice + "\n" + " error: " + (price - cachedPrice) + "\n" ); } } }
public EuropeanExercise(Date date) : base(Type.European) { dates_ = new InitializedList<Date>(1, date); }
public void testRegression() { // Testing fixed-coupon convertible bond in known regression case Date today = new Date(23, Month.December, 2008); Date tomorrow = today + 1; Settings.Instance.setEvaluationDate(tomorrow); Handle <Quote> u = new Handle <Quote>(new SimpleQuote(2.9084382818797443)); List <Date> dates = new InitializedList <Date>(25); List <double> forwards = new InitializedList <double>(25); dates[0] = new Date(29, Month.December, 2008); forwards[0] = 0.0025999342800; dates[1] = new Date(5, Month.January, 2009); forwards[1] = 0.0025999342800; dates[2] = new Date(29, Month.January, 2009); forwards[2] = 0.0053123275500; dates[3] = new Date(27, Month.February, 2009); forwards[3] = 0.0197049598721; dates[4] = new Date(30, Month.March, 2009); forwards[4] = 0.0220524845296; dates[5] = new Date(29, Month.June, 2009); forwards[5] = 0.0217076395643; dates[6] = new Date(29, Month.December, 2009); forwards[6] = 0.0230349627478; dates[7] = new Date(29, Month.December, 2010); forwards[7] = 0.0087631647476; dates[8] = new Date(29, Month.December, 2011); forwards[8] = 0.0219084299499; dates[9] = new Date(31, Month.December, 2012); forwards[9] = 0.0244798766219; dates[10] = new Date(30, Month.December, 2013); forwards[10] = 0.0267885498456; dates[11] = new Date(29, Month.December, 2014); forwards[11] = 0.0266922867562; dates[12] = new Date(29, Month.December, 2015); forwards[12] = 0.0271052126386; dates[13] = new Date(29, Month.December, 2016); forwards[13] = 0.0268829891648; dates[14] = new Date(29, Month.December, 2017); forwards[14] = 0.0264594744498; dates[15] = new Date(31, Month.December, 2018); forwards[15] = 0.0273450367424; dates[16] = new Date(30, Month.December, 2019); forwards[16] = 0.0294852614749; dates[17] = new Date(29, Month.December, 2020); forwards[17] = 0.0285556119719; dates[18] = new Date(29, Month.December, 2021); forwards[18] = 0.0305557764659; dates[19] = new Date(29, Month.December, 2022); forwards[19] = 0.0292244738422; dates[20] = new Date(29, Month.December, 2023); forwards[20] = 0.0263917004194; dates[21] = new Date(29, Month.December, 2028); forwards[21] = 0.0239626970243; dates[22] = new Date(29, Month.December, 2033); forwards[22] = 0.0216417108090; dates[23] = new Date(29, Month.December, 2038); forwards[23] = 0.0228343838422; dates[24] = new Date(31, Month.December, 2199); forwards[24] = 0.0228343838422; Handle <YieldTermStructure> r = new Handle <YieldTermStructure>(new InterpolatedForwardCurve <BackwardFlat>(dates, forwards, new Actual360())); Handle <BlackVolTermStructure> sigma = new Handle <BlackVolTermStructure>(new BlackConstantVol(tomorrow, new NullCalendar(), 21.685235548092248, new Thirty360(Thirty360.Thirty360Convention.BondBasis))); BlackProcess process = new BlackProcess(u, r, sigma); Handle <Quote> spread = new Handle <Quote>(new SimpleQuote(0.11498700678012874)); Date issueDate = new Date(23, Month.July, 2008); Date maturityDate = new Date(1, Month.August, 2013); Calendar calendar = new UnitedStates(); Schedule schedule = new MakeSchedule().from(issueDate) .to(maturityDate) .withTenor(new Period(6, TimeUnit.Months)) .withCalendar(calendar) .withConvention(BusinessDayConvention.Unadjusted).value(); int settlementDays = 3; Exercise exercise = new EuropeanExercise(maturityDate); double conversionRatio = 100.0 / 20.3175; List <double> coupons = new InitializedList <double>(schedule.size() - 1, 0.05); DayCounter dayCounter = new Thirty360(Thirty360.Thirty360Convention.BondBasis); CallabilitySchedule no_callability = new CallabilitySchedule(); DividendSchedule no_dividends = new DividendSchedule(); double redemption = 100.0; ConvertibleFixedCouponBond bond = new ConvertibleFixedCouponBond(exercise, conversionRatio, no_dividends, no_callability, spread, issueDate, settlementDays, coupons, dayCounter, schedule, redemption); bond.setPricingEngine(new BinomialConvertibleEngine <CoxRossRubinstein> (process, 600)); try { double x = bond.NPV(); // should throw; if not, an INF was not detected. QAssert.Fail("INF result was not detected: " + x + " returned"); } catch (Exception) { // as expected. Do nothing. // Note: we're expecting an Error we threw, not just any // exception. If something else is thrown, then there's // another problem and the test must fail. } }
public void testBond() { /* when deeply out-of-the-money, the value of the convertible bond * should equal that of the underlying plain-vanilla bond. */ // Testing out-of-the-money convertible bonds against vanilla bonds CommonVars vars = new CommonVars(); vars.conversionRatio = 1.0e-16; Exercise euExercise = new EuropeanExercise(vars.maturityDate); Exercise amExercise = new AmericanExercise(vars.issueDate, vars.maturityDate); int timeSteps = 1001; IPricingEngine engine = new BinomialConvertibleEngine <CoxRossRubinstein>(vars.process, timeSteps); Handle <YieldTermStructure> discountCurve = new Handle <YieldTermStructure>(new ForwardSpreadedTermStructure(vars.riskFreeRate, vars.creditSpread)); // zero-coupon Schedule schedule = new MakeSchedule().from(vars.issueDate) .to(vars.maturityDate) .withFrequency(Frequency.Once) .withCalendar(vars.calendar) .backwards().value(); ConvertibleZeroCouponBond euZero = new ConvertibleZeroCouponBond(euExercise, vars.conversionRatio, vars.no_dividends, vars.no_callability, vars.creditSpread, vars.issueDate, vars.settlementDays, vars.dayCounter, schedule, vars.redemption); euZero.setPricingEngine(engine); ConvertibleZeroCouponBond amZero = new ConvertibleZeroCouponBond(amExercise, vars.conversionRatio, vars.no_dividends, vars.no_callability, vars.creditSpread, vars.issueDate, vars.settlementDays, vars.dayCounter, schedule, vars.redemption); amZero.setPricingEngine(engine); ZeroCouponBond zero = new ZeroCouponBond(vars.settlementDays, vars.calendar, 100.0, vars.maturityDate, BusinessDayConvention.Following, vars.redemption, vars.issueDate); IPricingEngine bondEngine = new DiscountingBondEngine(discountCurve); zero.setPricingEngine(bondEngine); double tolerance = 1.0e-2 * (vars.faceAmount / 100.0); double error = Math.Abs(euZero.NPV() - zero.settlementValue()); if (error > tolerance) { QAssert.Fail("failed to reproduce zero-coupon bond price:" + "\n calculated: " + euZero.NPV() + "\n expected: " + zero.settlementValue() + "\n error: " + error); } error = Math.Abs(amZero.NPV() - zero.settlementValue()); if (error > tolerance) { QAssert.Fail("failed to reproduce zero-coupon bond price:" + "\n calculated: " + amZero.NPV() + "\n expected: " + zero.settlementValue() + "\n error: " + error); } // coupon List <double> coupons = new InitializedList <double>(1, 0.05); schedule = new MakeSchedule().from(vars.issueDate) .to(vars.maturityDate) .withFrequency(vars.frequency) .withCalendar(vars.calendar) .backwards().value(); ConvertibleFixedCouponBond euFixed = new ConvertibleFixedCouponBond(euExercise, vars.conversionRatio, vars.no_dividends, vars.no_callability, vars.creditSpread, vars.issueDate, vars.settlementDays, coupons, vars.dayCounter, schedule, vars.redemption); euFixed.setPricingEngine(engine); ConvertibleFixedCouponBond amFixed = new ConvertibleFixedCouponBond(amExercise, vars.conversionRatio, vars.no_dividends, vars.no_callability, vars.creditSpread, vars.issueDate, vars.settlementDays, coupons, vars.dayCounter, schedule, vars.redemption); amFixed.setPricingEngine(engine); FixedRateBond fixedBond = new FixedRateBond(vars.settlementDays, vars.faceAmount, schedule, coupons, vars.dayCounter, BusinessDayConvention.Following, vars.redemption, vars.issueDate); fixedBond.setPricingEngine(bondEngine); tolerance = 2.0e-2 * (vars.faceAmount / 100.0); error = Math.Abs(euFixed.NPV() - fixedBond.settlementValue()); if (error > tolerance) { QAssert.Fail("failed to reproduce fixed-coupon bond price:" + "\n calculated: " + euFixed.NPV() + "\n expected: " + fixedBond.settlementValue() + "\n error: " + error); } error = Math.Abs(amFixed.NPV() - fixedBond.settlementValue()); if (error > tolerance) { QAssert.Fail("failed to reproduce fixed-coupon bond price:" + "\n calculated: " + amFixed.NPV() + "\n expected: " + fixedBond.settlementValue() + "\n error: " + error); } // floating-rate IborIndex index = new Euribor1Y(discountCurve); int fixingDays = 2; List <double> gearings = new InitializedList <double>(1, 1.0); List <double> spreads = new List <double>(); ConvertibleFloatingRateBond euFloating = new ConvertibleFloatingRateBond(euExercise, vars.conversionRatio, vars.no_dividends, vars.no_callability, vars.creditSpread, vars.issueDate, vars.settlementDays, index, fixingDays, spreads, vars.dayCounter, schedule, vars.redemption); euFloating.setPricingEngine(engine); ConvertibleFloatingRateBond amFloating = new ConvertibleFloatingRateBond(amExercise, vars.conversionRatio, vars.no_dividends, vars.no_callability, vars.creditSpread, vars.issueDate, vars.settlementDays, index, fixingDays, spreads, vars.dayCounter, schedule, vars.redemption); amFloating.setPricingEngine(engine); IborCouponPricer pricer = new BlackIborCouponPricer(new Handle <OptionletVolatilityStructure>()); Schedule floatSchedule = new Schedule(vars.issueDate, vars.maturityDate, new Period(vars.frequency), vars.calendar, BusinessDayConvention.Following, BusinessDayConvention.Following, DateGeneration.Rule.Backward, false); FloatingRateBond floating = new FloatingRateBond(vars.settlementDays, vars.faceAmount, floatSchedule, index, vars.dayCounter, BusinessDayConvention.Following, fixingDays, gearings, spreads, new List <double?>(), new List <double?>(), false, vars.redemption, vars.issueDate); floating.setPricingEngine(bondEngine); Utils.setCouponPricer(floating.cashflows(), pricer); tolerance = 2.0e-2 * (vars.faceAmount / 100.0); error = Math.Abs(euFloating.NPV() - floating.settlementValue()); if (error > tolerance) { QAssert.Fail("failed to reproduce floating-rate bond price:" + "\n calculated: " + euFloating.NPV() + "\n expected: " + floating.settlementValue() + "\n error: " + error); } error = Math.Abs(amFloating.NPV() - floating.settlementValue()); if (error > tolerance) { QAssert.Fail("failed to reproduce floating-rate bond price:" + "\n calculated: " + amFloating.NPV() + "\n expected: " + floating.settlementValue() + "\n error: " + error); } }
public List<double> discountBond(List<double> rates) { List<double> discountFactors = new InitializedList<double>(size_); discountFactors[0] = 1.0 / (1.0 + rates[0] * accrualPeriod_[0]); for (int i = 1; i < size_; ++i) { discountFactors[i] = discountFactors[i - 1] / (1.0 + rates[i] * accrualPeriod_[i]); } return discountFactors; }
public void testSimpleCovarianceModels() { // Testing simple covariance models const int size = 10; const double tolerance = 1e-14; int i; LmCorrelationModel corrModel = new LmExponentialCorrelationModel(size, 0.1); Matrix recon = corrModel.correlation(0.0, null) - corrModel.pseudoSqrt(0.0, null) * Matrix.transpose(corrModel.pseudoSqrt(0.0, null)); for (i = 0; i < size; ++i) { for (int j = 0; j < size; ++j) { if (Math.Abs(recon[i, j]) > tolerance) { QAssert.Fail("Failed to reproduce correlation matrix" + "\n calculated: " + recon[i, j] + "\n expected: " + 0); } } } List <double> fixingTimes = new InitializedList <double>(size); for (i = 0; i < size; ++i) { fixingTimes[i] = 0.5 * i; } const double a = 0.2; const double b = 0.1; const double c = 2.1; const double d = 0.3; LmVolatilityModel volaModel = new LmLinearExponentialVolatilityModel(fixingTimes, a, b, c, d); LfmCovarianceProxy covarProxy = new LfmCovarianceProxy(volaModel, corrModel); LiborForwardModelProcess process = new LiborForwardModelProcess(size, makeIndex()); LiborForwardModel liborModel = new LiborForwardModel(process, volaModel, corrModel); for (double t = 0; t < 4.6; t += 0.31) { recon = covarProxy.covariance(t, null) - covarProxy.diffusion(t, null) * Matrix.transpose(covarProxy.diffusion(t, null)); for (int k = 0; k < size; ++k) { for (int j = 0; j < size; ++j) { if (Math.Abs(recon[k, j]) > tolerance) { QAssert.Fail("Failed to reproduce correlation matrix" + "\n calculated: " + recon[k, j] + "\n expected: " + 0); } } } Vector volatility = volaModel.volatility(t, null); for (int k = 0; k < size; ++k) { double expected = 0; if (k > 2 * t) { double T = fixingTimes[k]; expected = (a * (T - t) + d) * Math.Exp(-b * (T - t)) + c; } if (Math.Abs(expected - volatility[k]) > tolerance) { QAssert.Fail("Failed to reproduce volatities" + "\n calculated: " + volatility[k] + "\n expected: " + expected); } } } }
public void testSpreadDependency() { //"Testing swaption dependency on spread..."; CommonVars vars = new CommonVars(); double[] spreads = { -0.002, -0.001, 0.0, 0.001, 0.002 }; for (int i = 0; i < exercises.Length; i++) { for (int j = 0; j < lengths.Length; j++) { for (int k = 0; k < type.Length; k++) { Date exerciseDate = vars.calendar.advance(vars.today, exercises[i]); Date startDate = vars.calendar.advance(exerciseDate, vars.settlementDays, TimeUnit.Days); // store the results for different rates... List <double> values = new InitializedList <double>(spreads.Length); List <double> values_cash = new InitializedList <double>(spreads.Length); for (int l = 0; l < spreads.Length; l++) { VanillaSwap swap = new MakeVanillaSwap(lengths[j], vars.index, 0.06) .withEffectiveDate(startDate) .withFloatingLegSpread(spreads[l]) .withType(type[k]); Swaption swaption = vars.makeSwaption(swap, exerciseDate, 0.20); // FLOATING_POINT_EXCEPTION values[l] = swaption.NPV(); Swaption swaption_cash = vars.makeSwaption(swap, exerciseDate, 0.20, Settlement.Type.Cash); values_cash[l] = swaption_cash.NPV(); } // and check that they go the right way if (type[k] == VanillaSwap.Type.Payer) { for (int n = 0; n < spreads.Length - 1; n++) { if (values[n] > values[n + 1]) { Assert.Fail("NPV is decreasing with the spread " + "in a payer swaption (physical delivered):" + "\nexercise date: " + exerciseDate + "\nlength: " + lengths[j] + "\nvalue: " + values[n] + " for spread: " + spreads[n] + "\nvalue: " + values[n + 1] + " for spread: " + spreads[n + 1]); } if (values_cash[n] > values_cash[n + 1]) { Assert.Fail("NPV is decreasing with the spread " + "in a payer swaption (cash delivered):" + "\nexercise date: " + exerciseDate + "\nlength: " + lengths[j] + "\nvalue: " + values_cash[n] + " for spread: " + spreads[n] + "\nvalue: " + values_cash[n + 1] + " for spread: " + spreads[n + 1]); } } } else { for (int n = 0; n < spreads.Length - 1; n++) { if (values[n] < values[n + 1]) { Assert.Fail("NPV is increasing with the spread " + "in a receiver swaption (physical delivered):" + "\nexercise date: " + exerciseDate + "\nlength: " + lengths[j] + "\nvalue: " + values[n] + " for spread: " + spreads[n] + "\nvalue: " + values[n + 1] + " for spread: " + spreads[n + 1]); } if (values_cash[n] < values_cash[n + 1]) { Assert.Fail("NPV is increasing with the spread " + "in a receiver swaption (cash delivered):" + "\nexercise date: " + exerciseDate + "\nlength: " + lengths[j] + "\nvalue: " + values_cash[n] + " for spread: " + spreads[n] + "\nvalue: " + values_cash[n + 1] + " for spread: " + spreads[n + 1]); } } } } } } }
public void RiskStatisticsTest() { // ("Testing risk measures..."); IncrementalGaussianStatistics igs = new IncrementalGaussianStatistics(); RiskStatistics s = new RiskStatistics(); double[] averages = { -100.0, -1.0, 0.0, 1.0, 100.0 }; double[] sigmas = { 0.1, 1.0, 100.0 }; int i, j, k, N; N = (int)Math.Pow(2, 16) - 1; double dataMin, dataMax; List <double> data = new InitializedList <double>(N), weights = new InitializedList <double>(N); for (i = 0; i < averages.Length; i++) { for (j = 0; j < sigmas.Length; j++) { NormalDistribution normal = new NormalDistribution(averages[i], sigmas[j]); CumulativeNormalDistribution cumulative = new CumulativeNormalDistribution(averages[i], sigmas[j]); InverseCumulativeNormal inverseCum = new InverseCumulativeNormal(averages[i], sigmas[j]); SobolRsg rng = new SobolRsg(1); dataMin = double.MaxValue; dataMax = double.MinValue; for (k = 0; k < N; k++) { data[k] = inverseCum.value(rng.nextSequence().value[0]); dataMin = Math.Min(dataMin, data[k]); dataMax = Math.Max(dataMax, data[k]); weights[k] = 1.0; } igs.addSequence(data, weights); s.addSequence(data, weights); // checks double calculated, expected; double tolerance; if (igs.samples() != N) { QAssert.Fail("IncrementalGaussianStatistics: " + "wrong number of samples\n" + " calculated: " + igs.samples() + "\n" + " expected: " + N); } if (s.samples() != N) { QAssert.Fail("RiskStatistics: wrong number of samples\n" + " calculated: " + s.samples() + "\n" + " expected: " + N); } // weightSum() tolerance = 1e-10; expected = weights.Sum(); calculated = igs.weightSum(); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("IncrementalGaussianStatistics: " + "wrong sum of weights\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } calculated = s.weightSum(); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("RiskStatistics: wrong sum of weights\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } // min tolerance = 1e-12; expected = dataMin; calculated = igs.min(); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("IncrementalGaussianStatistics: " + "wrong minimum value\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } calculated = s.min(); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("RiskStatistics: " + "wrong minimum value\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } // max expected = dataMax; calculated = igs.max(); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("IncrementalGaussianStatistics: " + "wrong maximum value\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } calculated = s.max(); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("RiskStatistics: " + "wrong maximum value\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } // mean expected = averages[i]; tolerance = (expected == 0.0 ? 1.0e-13 : Math.Abs(expected) * 1.0e-13); calculated = igs.mean(); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("IncrementalGaussianStatistics: " + "wrong mean value" + " for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } calculated = s.mean(); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("RiskStatistics: wrong mean value" + " for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } // variance expected = sigmas[j] * sigmas[j]; tolerance = expected * 1.0e-1; calculated = igs.variance(); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("IncrementalGaussianStatistics: " + "wrong variance" + " for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } calculated = s.variance(); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("RiskStatistics: wrong variance" + " for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } // standardDeviation expected = sigmas[j]; tolerance = expected * 1.0e-1; calculated = igs.standardDeviation(); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("IncrementalGaussianStatistics: " + "wrong standard deviation" + " for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } calculated = s.standardDeviation(); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("RiskStatistics: wrong standard deviation" + " for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } // missing errorEstimate() test // skewness expected = 0.0; tolerance = 1.0e-4; calculated = igs.skewness(); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("IncrementalGaussianStatistics: " + "wrong skewness" + " for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } calculated = s.skewness(); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("RiskStatistics: wrong skewness" + " for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } // kurtosis expected = 0.0; tolerance = 1.0e-1; calculated = igs.kurtosis(); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("IncrementalGaussianStatistics: " + "wrong kurtosis" + " for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } calculated = s.kurtosis(); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("RiskStatistics: wrong kurtosis" + " for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } // percentile expected = averages[i]; tolerance = (expected == 0.0 ? 1.0e-3 : Math.Abs(expected * 1.0e-3)); calculated = igs.gaussianPercentile(0.5); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("IncrementalGaussianStatistics: " + "wrong Gaussian percentile" + " for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } calculated = s.gaussianPercentile(0.5); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("RiskStatistics: wrong Gaussian percentile" + " for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } calculated = s.percentile(0.5); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("RiskStatistics: wrong percentile" + " for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } // potential upside double upper_tail = averages[i] + 2.0 * sigmas[j], lower_tail = averages[i] - 2.0 * sigmas[j]; double twoSigma = cumulative.value(upper_tail); expected = Math.Max(upper_tail, 0.0); tolerance = (expected == 0.0 ? 1.0e-3 : Math.Abs(expected * 1.0e-3)); calculated = igs.gaussianPotentialUpside(twoSigma); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("IncrementalGaussianStatistics: " + "wrong Gaussian potential upside" + " for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } calculated = s.gaussianPotentialUpside(twoSigma); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("RiskStatistics: wrong Gaussian potential upside" + " for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } calculated = s.potentialUpside(twoSigma); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("RiskStatistics: wrong potential upside" + " for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } // just to check that GaussianStatistics<StatsHolder> does work StatsHolder h = new StatsHolder(s.mean(), s.standardDeviation()); GenericGaussianStatistics <StatsHolder> test = new GenericGaussianStatistics <StatsHolder>(h); expected = s.gaussianPotentialUpside(twoSigma); calculated = test.gaussianPotentialUpside(twoSigma); if (calculated != expected) { QAssert.Fail("GenericGaussianStatistics<StatsHolder> fails" + "\n calculated: " + calculated + "\n expected: " + expected); } // value-at-risk expected = -Math.Min(lower_tail, 0.0); tolerance = (expected == 0.0 ? 1.0e-3 : Math.Abs(expected * 1.0e-3)); calculated = igs.gaussianValueAtRisk(twoSigma); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("IncrementalGaussianStatistics: " + "wrong Gaussian value-at-risk" + " for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } calculated = s.gaussianValueAtRisk(twoSigma); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("RiskStatistics: wrong Gaussian value-at-risk" + " for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } calculated = s.valueAtRisk(twoSigma); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("RiskStatistics: wrong value-at-risk" + " for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } if (averages[i] > 0.0 && sigmas[j] < averages[i]) { // no data will miss the targets: // skip the rest of this iteration igs.reset(); s.reset(); continue; } // expected shortfall expected = -Math.Min(averages[i] - sigmas[j] * sigmas[j] * normal.value(lower_tail) / (1.0 - twoSigma), 0.0); tolerance = (expected == 0.0 ? 1.0e-4 : Math.Abs(expected) * 1.0e-2); calculated = igs.gaussianExpectedShortfall(twoSigma); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("IncrementalGaussianStatistics: " + "wrong Gaussian expected shortfall" + " for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } calculated = s.gaussianExpectedShortfall(twoSigma); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("RiskStatistics: wrong Gaussian expected shortfall" + " for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } calculated = s.expectedShortfall(twoSigma); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("RiskStatistics: wrong expected shortfall" + " for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } // shortfall expected = 0.5; tolerance = (expected == 0.0 ? 1.0e-3 : Math.Abs(expected * 1.0e-3)); calculated = igs.gaussianShortfall(averages[i]); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("IncrementalGaussianStatistics: " + "wrong Gaussian shortfall" + " for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } calculated = s.gaussianShortfall(averages[i]); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("RiskStatistics: wrong Gaussian shortfall" + " for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } calculated = s.shortfall(averages[i]); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("RiskStatistics: wrong shortfall" + " for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } // average shortfall expected = sigmas[j] / Math.Sqrt(2.0 * Const.M_PI) * 2.0; tolerance = expected * 1.0e-3; calculated = igs.gaussianAverageShortfall(averages[i]); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("IncrementalGaussianStatistics: " + "wrong Gaussian average shortfall" + " for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } calculated = s.gaussianAverageShortfall(averages[i]); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("RiskStatistics: wrong Gaussian average shortfall" + " for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } calculated = s.averageShortfall(averages[i]); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("RiskStatistics: wrong average shortfall" + " for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } // regret expected = sigmas[j] * sigmas[j]; tolerance = expected * 1.0e-1; calculated = igs.gaussianRegret(averages[i]); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("IncrementalGaussianStatistics: " + "wrong Gaussian regret(" + averages[i] + ") " + "for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } calculated = s.gaussianRegret(averages[i]); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("RiskStatistics: " + "wrong Gaussian regret(" + averages[i] + ") " + "for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } calculated = s.regret(averages[i]); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("RiskStatistics: " + "wrong regret(" + averages[i] + ") " + "for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } // downsideVariance expected = s.downsideVariance(); tolerance = (expected == 0.0 ? 1.0e-3 : Math.Abs(expected * 1.0e-3)); calculated = igs.downsideVariance(); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("IncrementalGaussianStatistics: " + "wrong downside variance" + "for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } calculated = igs.gaussianDownsideVariance(); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("IncrementalGaussianStatistics: " + "wrong Gaussian downside variance" + "for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } // downsideVariance if (averages[i] == 0.0) { expected = sigmas[j] * sigmas[j]; tolerance = expected * 1.0e-3; calculated = igs.downsideVariance(); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("IncrementalGaussianStatistics: " + "wrong downside variance" + "for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } calculated = igs.gaussianDownsideVariance(); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("IncrementalGaussianStatistics: " + "wrong Gaussian downside variance" + "for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } calculated = s.downsideVariance(); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("RiskStatistics: wrong downside variance" + "for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } calculated = s.gaussianDownsideVariance(); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("RiskStatistics: wrong Gaussian downside variance" + "for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } } igs.reset(); s.reset(); } } }
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); } } } }
static void Main(string[] args) { DateTime timer = DateTime.Now; /********************* *** MARKET DATA *** *********************/ Calendar calendar = new TARGET(); Date settlementDate = new Date(18, Month.September, 2008); // must be a business day settlementDate = calendar.adjust(settlementDate); int fixingDays = 3; int settlementDays = 3; Date todaysDate = calendar.advance(settlementDate, -fixingDays, TimeUnit.Days); // nothing to do with Date::todaysDate Settings.setEvaluationDate(todaysDate); Console.WriteLine("Today: {0}, {1}", todaysDate.DayOfWeek, todaysDate); Console.WriteLine("Settlement date: {0}, {1}", settlementDate.DayOfWeek, settlementDate); // Building of the bonds discounting yield curve /********************* *** RATE HELPERS *** *********************/ // RateHelpers are built from the above quotes together with // other instrument dependant infos. Quotes are passed in // relinkable handles which could be relinked to some other // data source later. // Common data // ZC rates for the short end double zc3mQuote=0.0096; double zc6mQuote=0.0145; double zc1yQuote=0.0194; Quote zc3mRate = new SimpleQuote(zc3mQuote); Quote zc6mRate = new SimpleQuote(zc6mQuote); Quote zc1yRate = new SimpleQuote(zc1yQuote); DayCounter zcBondsDayCounter = new Actual365Fixed(); RateHelper zc3m = new DepositRateHelper(new Handle<Quote>(zc3mRate), new Period(3, TimeUnit.Months), fixingDays, calendar, BusinessDayConvention.ModifiedFollowing, true, zcBondsDayCounter); RateHelper zc6m = new DepositRateHelper(new Handle<Quote>(zc6mRate), new Period(6, TimeUnit.Months), fixingDays, calendar, BusinessDayConvention.ModifiedFollowing, true, zcBondsDayCounter); RateHelper zc1y = new DepositRateHelper(new Handle<Quote>(zc1yRate), new Period(1, TimeUnit.Years), fixingDays, calendar, BusinessDayConvention.ModifiedFollowing, true, zcBondsDayCounter); // setup bonds double redemption = 100.0; const int numberOfBonds = 5; Date[] issueDates = { new Date (15, Month.March, 2005), new Date (15, Month.June, 2005), new Date (30, Month.June, 2006), new Date (15, Month.November, 2002), new Date (15, Month.May, 1987) }; Date[] maturities = { new Date (31, Month.August, 2010), new Date (31, Month.August, 2011), new Date (31, Month.August, 2013), new Date (15, Month.August, 2018), new Date (15, Month.May, 2038) }; double[] couponRates = { 0.02375, 0.04625, 0.03125, 0.04000, 0.04500 }; double[] marketQuotes = { 100.390625, 106.21875, 100.59375, 101.6875, 102.140625 }; List<SimpleQuote> quote = new List<SimpleQuote>(); for (int i=0; i<numberOfBonds; i++) { SimpleQuote cp = new SimpleQuote(marketQuotes[i]); quote.Add(cp); } List<RelinkableHandle<Quote>> quoteHandle = new InitializedList<RelinkableHandle<Quote>>(numberOfBonds); for (int i=0; i<numberOfBonds; i++) { quoteHandle[i].linkTo(quote[i]); } // Definition of the rate helpers List<FixedRateBondHelper> bondsHelpers = new List<FixedRateBondHelper>(); for (int i=0; i<numberOfBonds; i++) { Schedule schedule = new Schedule(issueDates[i], maturities[i], new Period(Frequency.Semiannual), new UnitedStates(UnitedStates.Market.GovernmentBond), BusinessDayConvention.Unadjusted, BusinessDayConvention.Unadjusted, DateGeneration.Rule.Backward, false); FixedRateBondHelper bondHelper = new FixedRateBondHelper(quoteHandle[i], settlementDays, 100.0, schedule, new List<double>() { couponRates[i] }, new ActualActual(ActualActual.Convention.Bond), BusinessDayConvention.Unadjusted, redemption, issueDates[i]); bondsHelpers.Add(bondHelper); } /********************* ** CURVE BUILDING ** *********************/ // Any DayCounter would be fine. // ActualActual::ISDA ensures that 30 years is 30.0 DayCounter termStructureDayCounter = new ActualActual(ActualActual.Convention.ISDA); double tolerance = 1.0e-15; // A depo-bond curve List<RateHelper> bondInstruments = new List<RateHelper>(); // Adding the ZC bonds to the curve for the short end bondInstruments.Add(zc3m); bondInstruments.Add(zc6m); bondInstruments.Add(zc1y); // Adding the Fixed rate bonds to the curve for the long end for (int i=0; i<numberOfBonds; i++) { bondInstruments.Add(bondsHelpers[i]); } YieldTermStructure bondDiscountingTermStructure = new PiecewiseYieldCurve<Discount,LogLinear>( settlementDate, bondInstruments, termStructureDayCounter, new List<Handle<Quote>>(), new List<Date>(), tolerance); // Building of the Libor forecasting curve // deposits double d1wQuote=0.043375; double d1mQuote=0.031875; double d3mQuote=0.0320375; double d6mQuote=0.03385; double d9mQuote=0.0338125; double d1yQuote=0.0335125; // swaps double s2yQuote=0.0295; double s3yQuote=0.0323; double s5yQuote=0.0359; double s10yQuote=0.0412; double s15yQuote=0.0433; /******************** *** QUOTES *** ********************/ // SimpleQuote stores a value which can be manually changed; // other Quote subclasses could read the value from a database // or some kind of data feed. // deposits Quote d1wRate = new SimpleQuote(d1wQuote); Quote d1mRate = new SimpleQuote(d1mQuote); Quote d3mRate = new SimpleQuote(d3mQuote); Quote d6mRate = new SimpleQuote(d6mQuote); Quote d9mRate = new SimpleQuote(d9mQuote); Quote d1yRate = new SimpleQuote(d1yQuote); // swaps Quote s2yRate = new SimpleQuote(s2yQuote); Quote s3yRate = new SimpleQuote(s3yQuote); Quote s5yRate = new SimpleQuote(s5yQuote); Quote s10yRate = new SimpleQuote(s10yQuote); Quote s15yRate = new SimpleQuote(s15yQuote); /********************* *** RATE HELPERS *** *********************/ // RateHelpers are built from the above quotes together with // other instrument dependant infos. Quotes are passed in // relinkable handles which could be relinked to some other // data source later. // deposits DayCounter depositDayCounter = new Actual360(); RateHelper d1w = new DepositRateHelper( new Handle<Quote>(d1wRate), new Period(1, TimeUnit.Weeks), fixingDays, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); RateHelper d1m = new DepositRateHelper( new Handle<Quote>(d1mRate), new Period(1, TimeUnit.Months), fixingDays, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); RateHelper d3m = new DepositRateHelper( new Handle<Quote>(d3mRate), new Period(3, TimeUnit.Months), fixingDays, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); RateHelper d6m = new DepositRateHelper( new Handle<Quote>(d6mRate), new Period(6, TimeUnit.Months), fixingDays, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); RateHelper d9m = new DepositRateHelper( new Handle<Quote>(d9mRate), new Period(9, TimeUnit.Months), fixingDays, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); RateHelper d1y = new DepositRateHelper( new Handle<Quote>(d1yRate), new Period(1, TimeUnit.Years), fixingDays, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); // setup swaps Frequency swFixedLegFrequency =Frequency.Annual; BusinessDayConvention swFixedLegConvention = BusinessDayConvention.Unadjusted; DayCounter swFixedLegDayCounter = new Thirty360(Thirty360.Thirty360Convention.European); IborIndex swFloatingLegIndex = new Euribor6M(); Period forwardStart = new Period(1, TimeUnit.Days); RateHelper s2y = new SwapRateHelper( new Handle<Quote>(s2yRate), new Period(2, TimeUnit.Years), calendar, swFixedLegFrequency, swFixedLegConvention, swFixedLegDayCounter, swFloatingLegIndex, new Handle<Quote>(),forwardStart); RateHelper s3y = new SwapRateHelper( new Handle<Quote>(s3yRate), new Period(3, TimeUnit.Years), calendar, swFixedLegFrequency, swFixedLegConvention, swFixedLegDayCounter, swFloatingLegIndex, new Handle<Quote>(),forwardStart); RateHelper s5y = new SwapRateHelper( new Handle<Quote>(s5yRate), new Period(5, TimeUnit.Years), calendar, swFixedLegFrequency, swFixedLegConvention, swFixedLegDayCounter, swFloatingLegIndex, new Handle<Quote>(),forwardStart); RateHelper s10y = new SwapRateHelper( new Handle<Quote>(s10yRate), new Period(10, TimeUnit.Years), calendar, swFixedLegFrequency, swFixedLegConvention, swFixedLegDayCounter, swFloatingLegIndex, new Handle<Quote>(),forwardStart); RateHelper s15y = new SwapRateHelper( new Handle<Quote>(s15yRate), new Period(15, TimeUnit.Years), calendar, swFixedLegFrequency, swFixedLegConvention, swFixedLegDayCounter, swFloatingLegIndex, new Handle<Quote>(),forwardStart); /********************* ** CURVE BUILDING ** *********************/ // Any DayCounter would be fine. // ActualActual::ISDA ensures that 30 years is 30.0 // A depo-swap curve List<RateHelper> depoSwapInstruments = new List<RateHelper>(); depoSwapInstruments.Add(d1w); depoSwapInstruments.Add(d1m); depoSwapInstruments.Add(d3m); depoSwapInstruments.Add(d6m); depoSwapInstruments.Add(d9m); depoSwapInstruments.Add(d1y); depoSwapInstruments.Add(s2y); depoSwapInstruments.Add(s3y); depoSwapInstruments.Add(s5y); depoSwapInstruments.Add(s10y); depoSwapInstruments.Add(s15y); YieldTermStructure depoSwapTermStructure = new PiecewiseYieldCurve<Discount,LogLinear>( settlementDate, depoSwapInstruments, termStructureDayCounter, new List<Handle<Quote> >(), new List<Date>(), tolerance); // Term structures that will be used for pricing: // the one used for discounting cash flows RelinkableHandle<YieldTermStructure> discountingTermStructure = new RelinkableHandle<YieldTermStructure>(); // the one used for forward rate forecasting RelinkableHandle<YieldTermStructure> forecastingTermStructure = new RelinkableHandle<YieldTermStructure>(); /********************* * BONDS TO BE PRICED * **********************/ // Common data double faceAmount = 100; // Pricing engine IPricingEngine bondEngine = new DiscountingBondEngine(discountingTermStructure); // Zero coupon bond ZeroCouponBond zeroCouponBond = new ZeroCouponBond( settlementDays, new UnitedStates(UnitedStates.Market.GovernmentBond), faceAmount, new Date(15, Month.August,2013), BusinessDayConvention.Following, 116.92, new Date(15, Month.August,2003)); zeroCouponBond.setPricingEngine(bondEngine); // Fixed 4.5% US Treasury Note Schedule fixedBondSchedule = new Schedule(new Date(15, Month.May, 2007), new Date(15,Month.May,2017), new Period(Frequency.Semiannual), new UnitedStates(UnitedStates.Market.GovernmentBond), BusinessDayConvention.Unadjusted, BusinessDayConvention.Unadjusted, DateGeneration.Rule.Backward, false); FixedRateBond fixedRateBond = new FixedRateBond( settlementDays, faceAmount, fixedBondSchedule, new List<double>() { 0.045 }, new ActualActual(ActualActual.Convention.Bond), BusinessDayConvention.ModifiedFollowing, 100.0, new Date(15, Month.May, 2007)); fixedRateBond.setPricingEngine(bondEngine); // Floating rate bond (3M USD Libor + 0.1%) // Should and will be priced on another curve later... RelinkableHandle<YieldTermStructure> liborTermStructure = new RelinkableHandle<YieldTermStructure>(); IborIndex libor3m = new USDLibor(new Period(3, TimeUnit.Months), liborTermStructure); libor3m.addFixing(new Date(17, Month.July, 2008),0.0278625); Schedule floatingBondSchedule = new Schedule(new Date(21, Month.October, 2005), new Date(21, Month.October, 2010), new Period(Frequency.Quarterly), new UnitedStates(UnitedStates.Market.NYSE), BusinessDayConvention.Unadjusted, BusinessDayConvention.Unadjusted, DateGeneration.Rule.Backward, true); FloatingRateBond floatingRateBond = new FloatingRateBond( settlementDays, faceAmount, floatingBondSchedule, libor3m, new Actual360(), BusinessDayConvention.ModifiedFollowing, 2, // Gearings new List<double>() { 1.0 }, // Spreads new List<double>() { 0.001 }, // Caps new List<double>(), // Floors new List<double>(), // Fixing in arrears true, 100.0, new Date(21, Month.October, 2005)); floatingRateBond.setPricingEngine(bondEngine); // Coupon pricers IborCouponPricer pricer = new BlackIborCouponPricer(); // optionLet volatilities double volatility = 0.0; Handle<OptionletVolatilityStructure> vol; vol = new Handle<OptionletVolatilityStructure>( new ConstantOptionletVolatility( settlementDays, calendar, BusinessDayConvention.ModifiedFollowing, volatility, new Actual365Fixed())); pricer.setCapletVolatility(vol); Utils.setCouponPricer(floatingRateBond.cashflows(),pricer); // Yield curve bootstrapping forecastingTermStructure.linkTo(depoSwapTermStructure); discountingTermStructure.linkTo(bondDiscountingTermStructure); // We are using the depo & swap curve to estimate the future Libor rates liborTermStructure.linkTo(depoSwapTermStructure); /*************** * BOND PRICING * ****************/ // write column headings int[] widths = { 18, 10, 10, 10 }; Console.WriteLine("{0,18}{1,10}{2,10}{3,10}", "", "ZC", "Fixed", "Floating"); string separator = " | "; int width = widths[0] + widths[1] + widths[2] + widths[3]; string rule = "".PadLeft(width, '-'), dblrule = "".PadLeft(width, '='); string tab = "".PadLeft(8, ' '); Console.WriteLine(rule); Console.WriteLine("Net present value".PadLeft(widths[0]) + "{0,10:n2}{1,10:n2}{2,10:n2}", zeroCouponBond.NPV(), fixedRateBond.NPV(), floatingRateBond.NPV()); Console.WriteLine("Clean price".PadLeft(widths[0]) + "{0,10:n2}{1,10:n2}{2,10:n2}", zeroCouponBond.cleanPrice(), fixedRateBond.cleanPrice(), floatingRateBond.cleanPrice()); Console.WriteLine("Dirty price".PadLeft(widths[0]) + "{0,10:n2}{1,10:n2}{2,10:n2}", zeroCouponBond.dirtyPrice(), fixedRateBond.dirtyPrice(), floatingRateBond.dirtyPrice()); Console.WriteLine("Accrued coupon".PadLeft(widths[0]) + "{0,10:n2}{1,10:n2}{2,10:n2}", zeroCouponBond.accruedAmount(), fixedRateBond.accruedAmount(), floatingRateBond.accruedAmount()); Console.WriteLine("Previous coupon".PadLeft(widths[0]) + "{0,10:0.00%}{1,10:0.00%}{2,10:0.00%}", "N/A", fixedRateBond.previousCoupon(), floatingRateBond.previousCoupon()); Console.WriteLine("Next coupon".PadLeft(widths[0]) + "{0,10:0.00%}{1,10:0.00%}{2,10:0.00%}", "N/A", fixedRateBond.nextCoupon(), floatingRateBond.nextCoupon()); Console.WriteLine("Yield".PadLeft(widths[0]) + "{0,10:0.00%}{1,10:0.00%}{2,10:0.00%}", zeroCouponBond.yield(new Actual360(), Compounding.Compounded, Frequency.Annual), fixedRateBond.yield(new Actual360(), Compounding.Compounded, Frequency.Annual), floatingRateBond.yield(new Actual360(), Compounding.Compounded, Frequency.Annual)); Console.WriteLine(); // Other computations Console.WriteLine("Sample indirect computations (for the floating rate bond): "); Console.WriteLine(rule); Console.WriteLine("Yield to Clean Price: {0:n2}", floatingRateBond.cleanPrice(floatingRateBond.yield(new Actual360(), Compounding.Compounded, Frequency.Annual), new Actual360(), Compounding.Compounded, Frequency.Annual, settlementDate)); Console.WriteLine("Clean Price to Yield: {0:0.00%}", floatingRateBond.yield(floatingRateBond.cleanPrice(),new Actual360(), Compounding.Compounded, Frequency.Annual, settlementDate)); /* "Yield to Price" "Price to Yield" */ Console.WriteLine(" \nRun completed in {0}", DateTime.Now - timer); Console.WriteLine(); Console.Write("Press any key to continue ..."); Console.ReadKey(); }
public void testLiborFixing() { // "Testing use of today's LIBOR fixings in swap curve..."); CommonVars vars = new CommonVars(); var swapHelpers = new InitializedList <RateHelper>(); IborIndex euribor6m = new Euribor6M(); for (int i = 0; i < vars.swaps; i++) { Handle <Quote> r = new Handle <Quote>(vars.rates[i + vars.deposits]); swapHelpers.Add(new SwapRateHelper(r, new Period(vars.swapData[i].n, vars.swapData[i].units), vars.calendar, vars.fixedLegFrequency, vars.fixedLegConvention, vars.fixedLegDayCounter, euribor6m)); } vars.termStructure = new PiecewiseYieldCurve <Discount, LogLinear>(vars.settlement, swapHelpers, new Actual360()); Handle <YieldTermStructure> curveHandle = new Handle <YieldTermStructure>(vars.termStructure); IborIndex index = new Euribor6M(curveHandle); for (int i = 0; i < vars.swaps; i++) { Period tenor = new Period(vars.swapData[i].n, vars.swapData[i].units); VanillaSwap swap = new MakeVanillaSwap(tenor, index, 0.0) .withEffectiveDate(vars.settlement) .withFixedLegDayCount(vars.fixedLegDayCounter) .withFixedLegTenor(new Period(vars.fixedLegFrequency)) .withFixedLegConvention(vars.fixedLegConvention) .withFixedLegTerminationDateConvention(vars.fixedLegConvention) .value(); double expectedRate = vars.swapData[i].rate / 100, estimatedRate = swap.fairRate(); double tolerance = 1.0e-9; if (Math.Abs(expectedRate - estimatedRate) > tolerance) { QAssert.Fail("before LIBOR fixing:\n" + vars.swapData[i].n + " year(s) swap:\n" + " estimated rate: " + (estimatedRate) + "\n" + " expected rate: " + (expectedRate)); } } Flag f = new Flag(); vars.termStructure.registerWith(f.update); f.lower(); index.addFixing(vars.today, 0.0425); if (!f.isUp()) { QAssert.Fail("Observer was not notified of rate fixing"); } for (int i = 0; i < vars.swaps; i++) { Period tenor = new Period(vars.swapData[i].n, vars.swapData[i].units); VanillaSwap swap = new MakeVanillaSwap(tenor, index, 0.0) .withEffectiveDate(vars.settlement) .withFixedLegDayCount(vars.fixedLegDayCounter) .withFixedLegTenor(new Period(vars.fixedLegFrequency)) .withFixedLegConvention(vars.fixedLegConvention) .withFixedLegTerminationDateConvention(vars.fixedLegConvention) .value(); double expectedRate = vars.swapData[i].rate / 100, estimatedRate = swap.fairRate(); double tolerance = 1.0e-9; if (Math.Abs(expectedRate - estimatedRate) > tolerance) { QAssert.Fail("after LIBOR fixing:\n" + vars.swapData[i].n + " year(s) swap:\n" + " estimated rate: " + (estimatedRate) + "\n" + " expected rate: " + (expectedRate)); } } }