当前位置: 首页 > 工具软件 > Interest.blog > 使用案例 >

C++:实现量化Interest Rate利率测试实例

夏侯和韵
2023-12-01

#include "interestrates.hpp"
#include "utilities.hpp"
#include <ql/interestrate.hpp>
#include <ql/math/rounding.hpp>
#include <ql/math/comparison.hpp>
#include <ql/time/daycounters/actual360.hpp>
#include <ql/utilities/dataformatters.hpp>
#include <iomanip>

using namespace QuantLib;
using namespace boost::unit_test_framework;

namespace {

    struct InterestRateData {
        Rate r;
        Compounding comp;
        Frequency freq;
        Time t;
        Compounding comp2;
        Frequency freq2;
        Rate expected;
        Size precision;
    };

}


void InterestRateTest::testConversions() {
    BOOST_TEST_MESSAGE("Testing interest-rate conversions...");

    InterestRateData cases[] = {
        // data from "Option Pricing Formulas", Haug, pag.181-182
        // Rate,Compounding,        Frequency,   Time, Compounding2,      Frequency2,  Rate2, precision
        {0.0800, Compounded,        Quarterly,   1.00, Continuous,            Annual, 0.0792, 4},
        {0.1200, Continuous,           Annual,   1.00, Compounded,            Annual, 0.1275, 4},
        {0.0800, Compounded,        Quarterly,   1.00, Compounded,            Annual, 0.0824, 4},
        {0.0700, Compounded,        Quarterly,   1.00, Compounded,        Semiannual, 0.0706, 4},
        // undocumented, but reasonable :)
        {0.0100, Compounded,           Annual,   1.00,     Simple,            Annual, 0.0100, 4},
        {0.0200,     Simple,           Annual,   1.00, Compounded,            Annual, 0.0200, 4},
        {0.0300, Compounded,       Semiannual,   0.50,     Simple,            Annual, 0.0300, 4},
        {0.0400,     Simple,           Annual,   0.50, Compounded,        Semiannual, 0.0400, 4},
        {0.0500, Compounded, EveryFourthMonth,  1.0/3,     Simple,            Annual, 0.0500, 4},
        {0.0600,     Simple,           Annual,  1.0/3, Compounded,  EveryFourthMonth, 0.0600, 4},
        {0.0500, Compounded,        Quarterly,   0.25,     Simple,            Annual, 0.0500, 4},
        {0.0600,     Simple,           Annual,   0.25, Compounded,         Quarterly, 0.0600, 4},
        {0.0700, Compounded,        Bimonthly,  1.0/6,     Simple,            Annual, 0.0700, 4},
        {0.0800,     Simple,           Annual,  1.0/6, Compounded,         Bimonthly, 0.0800, 4},
        {0.0900, Compounded,          Monthly, 1.0/12,     Simple,            Annual, 0.0900, 4},
        {0.1000,     Simple,           Annual, 1.0/12, Compounded,           Monthly, 0.1000, 4},

        {0.0300, SimpleThenCompounded,       Semiannual,   0.25,               Simple,            Annual, 0.0300, 4},
        {0.0300, SimpleThenCompounded,       Semiannual,   0.25,               Simple,        Semiannual, 0.0300, 4},
        {0.0300, SimpleThenCompounded,       Semiannual,   0.25,               Simple,         Quarterly, 0.0300, 4},
        {0.0300, SimpleThenCompounded,       Semiannual,   0.50,               Simple,            Annual, 0.0300, 4},
        {0.0300, SimpleThenCompounded,       Semiannual,   0.50,               Simple,        Semiannual, 0.0300, 4},
        {0.0300, SimpleThenCompounded,       Semiannual,   0.75,           Compounded,        Semiannual, 0.0300, 4},

        {0.0400,               Simple,       Semiannual,   0.25, SimpleThenCompounded,         Quarterly, 0.0400, 4},
        {0.0400,               Simple,       Semiannual,   0.25, SimpleThenCompounded,        Semiannual, 0.0400, 4},
        {0.0400,               Simple,       Semiannual,   0.25, SimpleThenCompounded,            Annual, 0.0400, 4},

        {0.0400,           Compounded,        Quarterly,   0.50, SimpleThenCompounded,         Quarterly, 0.0400, 4},
        {0.0400,               Simple,       Semiannual,   0.50, SimpleThenCompounded,        Semiannual, 0.0400, 4},
        {0.0400,               Simple,       Semiannual,   0.50, SimpleThenCompounded,            Annual, 0.0400, 4},

        {0.0400,           Compounded,        Quarterly,   0.75, SimpleThenCompounded,         Quarterly, 0.0400, 4},
        {0.0400,           Compounded,       Semiannual,   0.75, SimpleThenCompounded,        Semiannual, 0.0400, 4},
        {0.0400,               Simple,       Semiannual,   0.75, SimpleThenCompounded,            Annual, 0.0400, 4}
    };

    Rounding roundingPrecision;
    Rate r3, r2;
    Date d1 = Date::todaysDate(), d2;
    InterestRate ir, ir2, ir3, expectedIR;
    Real compoundf, error;
    DiscountFactor disc;


    for (auto& i : cases) {
        ir = InterestRate(i.r, Actual360(), i.comp, i.freq);
        d2 = d1 + timeToDays(i.t);
        roundingPrecision = Rounding(i.precision);

        // check that the compound factor is the inverse of the discount factor
        compoundf = ir.compoundFactor(d1, d2);
        disc = ir.discountFactor(d1, d2);
        error = std::fabs(disc-1.0/compoundf);
        if (error>1e-15)
            BOOST_FAIL("\n  " << ir
                       << std::setprecision(16)
                       << "\n  1.0/compound_factor: " << 1.0/compoundf
                       << "\n  discount_factor:     " << disc
                       << "\n  error:               " << error);

        // check that the equivalent InterestRate with *same* daycounter,
        // compounding, and frequency is the *same* InterestRate
        ir2 = ir.equivalentRate(ir.dayCounter(),
                                ir.compounding(),
                                ir.frequency(),
                                d1, d2);
        error = std::fabs(ir.rate()-ir2.rate());
        if (error>1e-15)
            BOOST_FAIL(std::setprecision(12)
                       << "\n    original interest rate: " << ir
                       << "\n  equivalent interest rate: " << ir2
                       << "\n                rate error: " << error);
        if (ir.dayCounter()!=ir2.dayCounter())
            BOOST_FAIL("\n day counter error"
                       << "\n original interest rate:   " << ir
                       << "\n equivalent interest rate: " << ir2);
        if (ir.compounding()!=ir2.compounding())
            BOOST_FAIL("\n compounding error"
                       << "\n original interest rate:   " << ir
                       << "\n equivalent interest rate: " << ir2);
        if (ir.frequency()!=ir2.frequency())
            BOOST_FAIL("\n frequency error"
                       << "\n    original interest rate: " << ir
                       << "\n  equivalent interest rate: " << ir2);

        // check that the equivalent rate with *same* daycounter,
        // compounding, and frequency is the *same* rate
        r2 = ir.equivalentRate(ir.dayCounter(),
                               ir.compounding(),
                               ir.frequency(),
                               d1, d2);
        error = std::fabs(ir.rate()-r2);
        if (error>1e-15)
            BOOST_FAIL(std::setprecision(12)
                       << "\n    original rate: " << ir
                       << "\n  equivalent rate: " << io::rate(r2)
                       << "\n            error: " << error);

        // check that the equivalent InterestRate with *different*
        // compounding, and frequency is the *expected* InterestRate
        ir3 = ir.equivalentRate(ir.dayCounter(), i.comp2, i.freq2, d1, d2);
        expectedIR = InterestRate(i.expected, ir.dayCounter(), i.comp2, i.freq2);
        r3 = roundingPrecision(ir3.rate());
        error = std::fabs(r3-expectedIR.rate());
        if (error>1.0e-17)
            BOOST_FAIL(std::setprecision(i.precision + 1)
                       << "\n               original interest rate: " << ir
                       << "\n  calculated equivalent interest rate: " << ir3
                       << "\n            truncated equivalent rate: " << io::rate(r3)
                       << "\n    expected equivalent interest rate: " << expectedIR
                       << "\n                           rate error: " << error);
        if (ir3.dayCounter()!=expectedIR.dayCounter())
            BOOST_FAIL("\n day counter error"
                       << "\n    original interest rate: " << ir3
                       << "\n  equivalent interest rate: " << expectedIR);
        if (ir3.compounding()!=expectedIR.compounding())
            BOOST_FAIL("\n compounding error"
                       << "\n    original interest rate: " << ir3
                       << "\n  equivalent interest rate: " << expectedIR);
        if (ir3.frequency()!=expectedIR.frequency())
            BOOST_FAIL("\n frequency error"
                       << "\n    original interest rate: " << ir3
                       << "\n  equivalent interest rate: " << expectedIR);

        // check that the equivalent rate with *different*
        // compounding, and frequency is the *expected* rate
        r3 = ir.equivalentRate(ir.dayCounter(), i.comp2, i.freq2, d1, d2);
        r3 = roundingPrecision(r3);
        error = std::fabs(r3 - i.expected);
        if (error>1.0e-17)
            BOOST_FAIL(std::setprecision(i.precision - 2)
                       << "\n  calculated equivalent rate: " << io::rate(r3)
                       << "\n    expected equivalent rate: " << io::rate(i.expected)
                       << "\n                       error: " << error);
    }
}

test_suite* InterestRateTest::suite() {
    auto* suite = BOOST_TEST_SUITE("Interest Rate tests");
    suite->add(QUANTLIB_TEST_CASE(&InterestRateTest::testConversions));
    return suite;
}


该博文为原创文章,未经博主同意不得转。
本文章博客地址:https://cplusplus.blog.csdn.net/article/details/128364227

 类似资料: