diff --git a/ql/methods/finitedifferences/operators/fdmwienerop.cpp b/ql/methods/finitedifferences/operators/fdmwienerop.cpp index 742e67b6dd..59cd4e88c9 100644 --- a/ql/methods/finitedifferences/operators/fdmwienerop.cpp +++ b/ql/methods/finitedifferences/operators/fdmwienerop.cpp @@ -18,7 +18,7 @@ */ -/*! \file fdmndimwienerop.cpp +/*! \file fdmwienerop.cpp */ #include diff --git a/ql/methods/finitedifferences/operators/fdmwienerop.hpp b/ql/methods/finitedifferences/operators/fdmwienerop.hpp index 2cdc7f65b3..85d7dd58bc 100644 --- a/ql/methods/finitedifferences/operators/fdmwienerop.hpp +++ b/ql/methods/finitedifferences/operators/fdmwienerop.hpp @@ -55,7 +55,6 @@ namespace QuantLib { const ext::shared_ptr rTS_; std::vector > ops_; Rate r_; - }; } #endif diff --git a/ql/pricingengines/basket/choibasketengine.hpp b/ql/pricingengines/basket/choibasketengine.hpp index 799efc0f68..9e263ad009 100644 --- a/ql/pricingengines/basket/choibasketengine.hpp +++ b/ql/pricingengines/basket/choibasketengine.hpp @@ -35,7 +35,7 @@ namespace QuantLib { Spread, Basket and Asian Options", Jaehyuk Choi, 2018 https://papers.ssrn.com/sol3/papers.cfm?abstract_id=2913048 - Python implementation from the author of the paper is also available + A Python implementation from the author of the paper is also available https://github.com/PyFE/PyFENG \ingroup basketengines @@ -45,8 +45,7 @@ namespace QuantLib { */ class ChoiBasketEngine : public BasketOption::engine { public: - // lambda controls the precision, - // fast: 4, accurate: 8, high precision: 20 + // lambda controls the integration order and the precision of the result. ChoiBasketEngine( std::vector > processes, Matrix rho, diff --git a/ql/pricingengines/basket/denglizhoubasketengine.cpp b/ql/pricingengines/basket/denglizhoubasketengine.cpp index bb453d5688..bfcc7be699 100644 --- a/ql/pricingengines/basket/denglizhoubasketengine.cpp +++ b/ql/pricingengines/basket/denglizhoubasketengine.cpp @@ -17,7 +17,6 @@ FOR A PARTICULAR PURPOSE. See the license for more details. */ -#include "denglizhoubasketengine.hpp" #include #include @@ -25,6 +24,7 @@ #include #include #include +#include namespace QuantLib { @@ -62,7 +62,6 @@ namespace QuantLib { QL_REQUIRE(avgPayoff, "average or spread basket payoff expected"); - // sort assets by their weight const Array weights = avgPayoff->weights(); QL_REQUIRE(n_ == weights.size() && n_ > 1, "wrong number of weights arguments in payoff"); diff --git a/ql/pricingengines/basket/fdndimblackscholesvanillaengine.hpp b/ql/pricingengines/basket/fdndimblackscholesvanillaengine.hpp index f8d2174067..a7378f4337 100644 --- a/ql/pricingengines/basket/fdndimblackscholesvanillaengine.hpp +++ b/ql/pricingengines/basket/fdndimblackscholesvanillaengine.hpp @@ -50,7 +50,7 @@ namespace QuantLib { const FdmSchemeDesc& schemeDesc = FdmSchemeDesc::Douglas()); - // Auto-scaling of grids, larges eigenvalue gets xGrid size. + // Auto-scaling of grids, largest eigenvalue gets xGrid size. FdndimBlackScholesVanillaEngine( std::vector > processes, Matrix rho, diff --git a/ql/pricingengines/basket/operatorsplittingspreadengine.cpp b/ql/pricingengines/basket/operatorsplittingspreadengine.cpp index 149cbc8d8a..d8f876bb25 100644 --- a/ql/pricingengines/basket/operatorsplittingspreadengine.cpp +++ b/ql/pricingengines/basket/operatorsplittingspreadengine.cpp @@ -68,7 +68,7 @@ namespace QuantLib { QL_REQUIRE(order_ == Second, "unknown approximation type"); /* - In the original paper the second order was calculated using numerical differentiation. + In the original paper, the second-order approximation was computed using numerical differentiation. The following Mathematica scripts calculates the approximation to the n'th order. vol2Hat[R2_] := vol2*(R2 - K)/R2 diff --git a/ql/pricingengines/basket/operatorsplittingspreadengine.hpp b/ql/pricingengines/basket/operatorsplittingspreadengine.hpp index 5b5e824d71..e5132ab3b2 100644 --- a/ql/pricingengines/basket/operatorsplittingspreadengine.hpp +++ b/ql/pricingengines/basket/operatorsplittingspreadengine.hpp @@ -28,7 +28,7 @@ namespace QuantLib { - //! Pricing engine for spread option on two futures + //! Pricing engine for spread options with two assets /*! Chi-Fai Lo, Pricing Spread Options by the Operator Splitting Method, https://papers.ssrn.com/sol3/papers.cfm?abstract_id=2429696 diff --git a/ql/pricingengines/basket/singlefactorbsmbasketengine.cpp b/ql/pricingengines/basket/singlefactorbsmbasketengine.cpp index 9ea29061e8..5d430ea60a 100644 --- a/ql/pricingengines/basket/singlefactorbsmbasketengine.cpp +++ b/ql/pricingengines/basket/singlefactorbsmbasketengine.cpp @@ -140,7 +140,6 @@ namespace QuantLib { QL_REQUIRE(payoff, "non-plain vanilla payoff given"); const Real strike = payoff->strike(); - // sort assets by their weight const Array weights = avgPayoff->weights(); QL_REQUIRE(n_ == weights.size(), "wrong number of weights arguments in payoff"); diff --git a/ql/pricingengines/basket/singlefactorbsmbasketengine.hpp b/ql/pricingengines/basket/singlefactorbsmbasketengine.hpp index 5771458255..f960f189a1 100644 --- a/ql/pricingengines/basket/singlefactorbsmbasketengine.hpp +++ b/ql/pricingengines/basket/singlefactorbsmbasketengine.hpp @@ -39,27 +39,27 @@ namespace QuantLib { \ingroup basketengines */ - class SumExponentialsRootSolver { - public: - enum Strategy {Ridder, Newton, Brent, Halley}; + class SumExponentialsRootSolver { + public: + enum Strategy {Ridder, Newton, Brent, Halley}; - SumExponentialsRootSolver(Array a, Array sig, Real K); + SumExponentialsRootSolver(Array a, Array sig, Real K); - Real operator()(Real x) const; - Real derivative(Real x) const; - Real secondDerivative(Real x) const; + Real operator()(Real x) const; + Real derivative(Real x) const; + Real secondDerivative(Real x) const; - Real getRoot(Real xTol = 1e6*QL_EPSILON, Strategy strategy = Brent) const; + Real getRoot(Real xTol = 1e6*QL_EPSILON, Strategy strategy = Brent) const; - Size getFCtr() const; - Size getDerivativeCtr() const; - Size getSecondDerivativeCtr() const; + Size getFCtr() const; + Size getDerivativeCtr() const; + Size getSecondDerivativeCtr() const; - private: - const Array a_, sig_; - const Real K_; - mutable Size fCtr_, fPrimeCtr_, fDoublePrimeCtr_; - }; + private: + const Array a_, sig_; + const Real K_; + mutable Size fCtr_, fPrimeCtr_, fDoublePrimeCtr_; + }; class SingleFactorBsmBasketEngine : public BasketOption::engine { public: diff --git a/test-suite/basketoption.cpp b/test-suite/basketoption.cpp index 488deb13e1..ef49b2284c 100755 --- a/test-suite/basketoption.cpp +++ b/test-suite/basketoption.cpp @@ -1772,51 +1772,51 @@ BOOST_AUTO_TEST_CASE(testRootOfSumExponentials) { MersenneTwisterUniformRng mt(42); for (auto strategy: { - std::make_tuple("Brent", SumExponentialsRootSolver::Brent), - std::make_tuple("Newton", SumExponentialsRootSolver::Newton), - std::make_tuple("Ridder", SumExponentialsRootSolver::Ridder), - std::make_tuple("Halley", SumExponentialsRootSolver::Halley) - }) { - - Size fCtr = 0; - const Size n = 10000; - const Real tol = 1e8*QL_EPSILON; - const Real acc = 1e-4*tol; - IncrementalStatistics stats; - - for (Size i=0; i < n; ++i) { - const Size n = (mt.nextInt32() % 10)+1; - Array a(n), sig(n); - const Real offset = (mt.nextReal() < 0.3)? -1.0 : 0.0; - for (Size j=0; j < n; ++j) { - a[j] = mt.nextReal() + offset; - sig[j] = copysign(1.0, a[j])*mt.nextReal(); - } - const Real kMin = SumExponentialsRootSolver(a, sig, 0.0)(-10.0); - const Real kMax = SumExponentialsRootSolver(a, sig, 0.0)( 10.0); - const Real K = (kMax - kMin)*mt.nextReal() + kMin; - - const Real xValue = SumExponentialsRootSolver(a, sig, K) - .getRoot(acc, SumExponentialsRootSolver::Brent); + std::make_tuple("Brent", SumExponentialsRootSolver::Brent), + std::make_tuple("Newton", SumExponentialsRootSolver::Newton), + std::make_tuple("Ridder", SumExponentialsRootSolver::Ridder), + std::make_tuple("Halley", SumExponentialsRootSolver::Halley) + }) { + + Size fCtr = 0; + const Size n = 10000; + const Real tol = 1e8*QL_EPSILON; + const Real acc = 1e-4*tol; + IncrementalStatistics stats; + + for (Size i=0; i < n; ++i) { + const Size n = (mt.nextInt32() % 10)+1; + Array a(n), sig(n); + const Real offset = (mt.nextReal() < 0.3)? -1.0 : 0.0; + for (Size j=0; j < n; ++j) { + a[j] = mt.nextReal() + offset; + sig[j] = copysign(1.0, a[j])*mt.nextReal(); + } + const Real kMin = SumExponentialsRootSolver(a, sig, 0.0)(-10.0); + const Real kMax = SumExponentialsRootSolver(a, sig, 0.0)( 10.0); + const Real K = (kMax - kMin)*mt.nextReal() + kMin; + + const Real xValue = SumExponentialsRootSolver(a, sig, K) + .getRoot(acc, SumExponentialsRootSolver::Brent); const SumExponentialsRootSolver solver(a, sig, K); - const Real xRoot = solver.getRoot(tol, std::get<1>(strategy)); + const Real xRoot = solver.getRoot(tol, std::get<1>(strategy)); - stats.add(xValue - xRoot); - fCtr += solver.getFCtr() + solver.getDerivativeCtr() + solver.getSecondDerivativeCtr(); - } + stats.add(xValue - xRoot); + fCtr += solver.getFCtr() + solver.getDerivativeCtr() + solver.getSecondDerivativeCtr(); + } - if (fCtr > 15*n) { + if (fCtr > 15*n) { BOOST_FAIL("too many function calls needed for solver " << std::get<0>(strategy)); - } + } - if (stats.standardDeviation() > 10*tol) { + if (stats.standardDeviation() > 10*tol) { BOOST_FAIL("failed to find root of sum of exponentials" << "\n solver : " << std::get<0>(strategy) << std::fixed << std::setprecision(15) << "\n stdev : " << stats.standardDeviation() << "\n tolerance: " << tol); - } + } } } @@ -1949,11 +1949,11 @@ BOOST_AUTO_TEST_CASE(testGoldenChoiBasketEngineExample) { const ext::shared_ptr& spot, Rate q, Volatility vol) -> ext::shared_ptr { return ext::make_shared( - Handle(spot), - Handle(flatRate(today, q, dc)), - rTS, - Handle(flatVol(today, vol, dc)) - ); + Handle(spot), + Handle(flatRate(today, q, dc)), + rTS, + Handle(flatVol(today, vol, dc)) + ); }; const std::vector > @@ -2189,7 +2189,7 @@ BOOST_AUTO_TEST_CASE(testSpreadAndBasketBenchmarks) { {11.5795246248372834, 8.11486124233140238, 5.36890684802773066, 3.35146299782513601, 1.97711593318812251} }, - // unknown + // new { {80, 120, 100, 100}, {0.3, 0.4, 0.2, 0.35}, {0.01, 0.03, 0.07, 0.04}, 0.03, {{{1.0, 0.5, 0.35, 0.35}, @@ -2451,8 +2451,8 @@ BOOST_AUTO_TEST_CASE(testFdmAmericanBasketOptions) { << "\n tolerance: " << tol); } -BOOST_AUTO_TEST_CASE(testPrecisionAmericanBasketOptions) { - BOOST_TEST_MESSAGE("Testing high precision American Options using multi-dim FDM..."); +BOOST_AUTO_TEST_CASE(testAccurateAmericanBasketOptions) { + BOOST_TEST_MESSAGE("Testing high precision American Options Pricing using multi-dim FDM..."); const DayCounter dc = Actual365Fixed(); const Date today = Date(28, October, 2024); diff --git a/test-suite/matrices.cpp b/test-suite/matrices.cpp index 76e45eab6e..6e42e4accd 100644 --- a/test-suite/matrices.cpp +++ b/test-suite/matrices.cpp @@ -913,13 +913,13 @@ BOOST_AUTO_TEST_CASE(testCholeskySolverForIncomplete) { } namespace { - void QL_CHECK_CLOSE_ARRAY_TOL( - const Array& actual, const Array& expected, Real tol) { - BOOST_REQUIRE(actual.size() == expected.size()); - for (auto i = 0u; i < actual.size(); i++) { - BOOST_CHECK_SMALL(actual[i] - expected[i], tol); - } - } + void QL_CHECK_CLOSE_ARRAY_TOL( + const Array& actual, const Array& expected, Real tol) { + BOOST_REQUIRE(actual.size() == expected.size()); + for (auto i = 0u; i < actual.size(); i++) { + BOOST_CHECK_SMALL(actual[i] - expected[i], tol); + } + } } BOOST_AUTO_TEST_CASE(testHouseholderTransformation) { @@ -928,23 +928,23 @@ BOOST_AUTO_TEST_CASE(testHouseholderTransformation) { MersenneTwisterUniformRng rng(1234); const auto I = [](Size i) -> Matrix { - Matrix id(i, i, 0.0); - for (Size j=0; j < i; ++j) - id[j][j] = 1.0; + Matrix id(i, i, 0.0); + for (Size j=0; j < i; ++j) + id[j][j] = 1.0; - return id; + return id; }; for (Size i=1; i < 10; ++i) { - Array v(i), x(i); - for (Size j=0; j < i; ++j) { - v[j] = rng.nextReal()-0.5; - x[j] = rng.nextReal()-0.5; - } - - const Array expected = (I(i)- 2.0*outerProduct(v, v))*x; - const Array calculated = HouseholderTransformation(v)(x); - QL_CHECK_CLOSE_ARRAY_TOL(calculated, expected, 1e4*QL_EPSILON); + Array v(i), x(i); + for (Size j=0; j < i; ++j) { + v[j] = rng.nextReal()-0.5; + x[j] = rng.nextReal()-0.5; + } + + const Array expected = (I(i)- 2.0*outerProduct(v, v))*x; + const Array calculated = HouseholderTransformation(v)(x); + QL_CHECK_CLOSE_ARRAY_TOL(calculated, expected, 1e4*QL_EPSILON); } } @@ -954,24 +954,24 @@ BOOST_AUTO_TEST_CASE(testHouseholderReflection) { const Real tol=1e4*QL_EPSILON; const auto e = [](Size n, Size m=0) -> Array { - Array e(n, 0.0); - e[m] = 1.0; - return e; + Array e(n, 0.0); + e[m] = 1.0; + return e; }; for (Size i=0; i < 5; ++i) { - QL_CHECK_CLOSE_ARRAY_TOL( - HouseholderReflection(e(5))(e(5, i)), e(5), tol); - QL_CHECK_CLOSE_ARRAY_TOL( - HouseholderReflection(e(5))(M_PI*e(5, i)), M_PI*e(5), tol); - QL_CHECK_CLOSE_ARRAY_TOL( - HouseholderReflection(e(5))( - e(5, i) + e(5)), - ((i==0)? 2.0 : M_SQRT2)*e(5), tol); + QL_CHECK_CLOSE_ARRAY_TOL( + HouseholderReflection(e(5))(e(5, i)), e(5), tol); + QL_CHECK_CLOSE_ARRAY_TOL( + HouseholderReflection(e(5))(M_PI*e(5, i)), M_PI*e(5), tol); + QL_CHECK_CLOSE_ARRAY_TOL( + HouseholderReflection(e(5))( + e(5, i) + e(5)), + ((i==0)? 2.0 : M_SQRT2)*e(5), tol); } // limits - for (Real x=10; x > 1e-50; x*=0.1) { + for (Real x=10; x > 1e-50; x*=0.1) { QL_CHECK_CLOSE_ARRAY_TOL( HouseholderReflection(e(3))( Array({10.0, x, 0})), @@ -983,7 +983,7 @@ BOOST_AUTO_TEST_CASE(testHouseholderReflection) { Array({10.0, x, 1e-3})), std::sqrt(10.0*10.0+x*x+1e-3*1e-3)*e(3), tol ); - } + } MersenneTwisterUniformRng rng(1234);