Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TreeSwaptionEngine mispricing #1143

Closed
ralfkonrad opened this issue Jul 9, 2021 · 3 comments · Fixed by #1327
Closed

TreeSwaptionEngine mispricing #1143

ralfkonrad opened this issue Jul 9, 2021 · 3 comments · Fixed by #1327

Comments

@ralfkonrad
Copy link
Contributor

Inspired by the problem in #930 I have tested the same for the TreeSwaptionEngine where we use the same snapping time mechanism as in the TreeCallableFixedRateBondEngine.

We have a similar problem here as well. The coupon date is at 2030-05-15 and when we change the call dates the next day the FdHullWhiteSwaptionEngine calculates a jump from 10.26 to 28.79 regarding. The TreeSwaptionEngine price jumps only seven days later.

Probably not that severe as in the TreeCallableFixedRateBondEngine as call dates shortly after coupon dates are not very common but I think the problem of misordered events is the same here.

Testing snap of exercise dates for discretized swaption...
Call date          FD    Tree
2030-05-06      10.11   11.04
2030-05-07      10.13   10.98
2030-05-08      10.15   10.92
2030-05-09      10.16   10.85
2030-05-10      10.18   10.78
2030-05-13      10.23   10.69
2030-05-14      10.25   10.83
2030-05-15      10.26   10.96
2030-05-16      28.79   10.92
2030-05-17      28.83   10.88
2030-05-20      28.94   10.97
2030-05-21      28.98   10.80
2030-05-22      29.01   10.69
2030-05-23      29.05   30.97
2030-05-24      29.09   30.99
    BOOST_TEST_MESSAGE("Testing snap of exercise dates for discretized swaption...");

    Date today = Date(8, Jul, 2021);
    SavedSettings backup;
    Settings::instance().evaluationDate() = today;

    RelinkableHandle<YieldTermStructure> termStructure;
    termStructure.linkTo(ext::make_shared<FlatForward>(today, 0.02, Actual365Fixed()));

    auto makeBermudanSwaption = [&today, &termStructure](Date callDate) {
        auto effectiveDate = Date(15, May, 2025);
        auto index = ext::make_shared<Euribor3M>(termStructure);
        ext::shared_ptr<VanillaSwap> swap = MakeVanillaSwap(Period(10, Years), index, 0.05)
                                                .withEffectiveDate(effectiveDate)
                                                .withNominal(10000.00)
                                                .withType(Swap::Type::Payer);

        std::vector<Date> exerciseDates{effectiveDate, callDate};
        auto bermudanExercise = ext::make_shared<BermudanExercise>(exerciseDates);
        auto bermudanSwaption = ext::make_shared<Swaption>(swap, bermudanExercise);

        return bermudanSwaption;
    };

    BOOST_TEST_MESSAGE("Call date\t   FD\t Tree");
    for (int i = -10; i < 11; i++) {
        static auto initialCallDate = Date(15, May, 2030);
        static auto calendar = Euribor3M().fixingCalendar();

        auto callDate = initialCallDate + i * Days;
        if (calendar.isBusinessDay(callDate)) {
            auto bermudanSwaption = makeBermudanSwaption(callDate);

            auto model = ext::make_shared<HullWhite>(termStructure);

            bermudanSwaption->setPricingEngine(ext::make_shared<FdHullWhiteSwaptionEngine>(model));
            auto npvFD = bermudanSwaption->NPV();

            bermudanSwaption->setPricingEngine(ext::make_shared<TreeSwaptionEngine>(model, 40));
            auto npvTree = bermudanSwaption->NPV();

            BOOST_TEST_MESSAGE(io::iso_date(callDate) << "\t" << std::fixed << std::setprecision(2)
                                                      << std::setw(5) << npvFD << "\t" << npvTree);
        }
    }
@lballabio
Copy link
Owner

Thanks, Ralf. May you also check what happens if you remove the bit of code that changes the call dates?

@ralfkonrad
Copy link
Contributor Author

Sure!

Now TreeSwaptionEngine jumps at 2030-05-16 as well.

But we see the numerical issue why the dates are snapped. The FdHullWhiteSwaptionEngine is monotonically increasing which seems reasonable to me. But TreeSwaptionEngine isn't even one month later. I haven't played around with the timeSteps, this might help (a bit?!).

image

image

Call date          FD    Tree
2030-05-06      10.11   11.04
2030-05-07      10.13   10.98
2030-05-08      10.15   10.92
2030-05-09      10.16   10.85
2030-05-10      10.18   10.78
2030-05-13      10.23   10.69
2030-05-14      10.25   10.83
2030-05-15      10.26   10.96
2030-05-16      28.79   30.78
2030-05-17      28.83   30.78
2030-05-20      28.94   30.88
2030-05-21      28.98   30.90
2030-05-22      29.01   30.78
2030-05-23      29.05   30.97
2030-05-24      29.09   30.99
2030-05-27      29.20   31.19
2030-05-28      29.23   31.16
2030-05-29      29.27   31.05
2030-05-30      29.31   31.19
2030-05-31      29.34   31.39
2030-06-03      29.45   31.13
2030-06-04      29.49   31.27
2030-06-05      29.53   31.47
2030-06-06      29.56   31.64
2030-06-07      29.60   31.73
2030-06-10      29.71   31.47
2030-06-11      29.75   31.27
2030-06-12      29.78   31.45
2030-06-13      29.82   31.53
2030-06-14      29.86   31.70

I simply used return false here. I guess that's what you meant?

        bool withinPreviousWeek(const Date& d1, const Date& d2) {
            return false;
            // return d2 >= d1-7 && d2 <= d1;
        }

        bool withinNextWeek(const Date& d1, const Date& d2) {
            return false;
            // return d2 >= d1 && d2 <= d1 + 7;
        }

@github-actions
Copy link
Contributor

This issue was automatically marked as stale because it has been open 60 days with no activity. Remove stale label or comment, or this will be closed in two weeks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants