Welcome back.

It’s been a while, and it’s been even longer since I posted new content from Implementing QuantLib. This post starts a series on the new finite-difference framework. As usual, my goal is to shame myself into writing more when I realize that I’m falling behind any reasonable blog schedule; in order to give me a head-start, this one is just a short introduction.

Some news. First: we had to change dates for my next Introduction to QuantLib Development course in London. It will be on November 14th to 16th, 2016. More details and a registration form are at this link.

Second: a couple of weeks ago, the ineffable Dirk Eddelbuettel has released RQuantLib 0.4.3; I’ll leave it to his own blog post to give credit where credit is due. Well, except to himself, so I’ll step in and give credit to him. So there.

And last: me and Goutham pushed an update to the QuantLib Python Cookbook. He added a chapter on callable bonds and updated the one on bootstrapping a treasury curve; I added a couple of chapters on avoiding glitches in the library that might bite you.

Follow me on Twitter if you want to be notified of new posts, or add me to your Google+ circles, or subscribe via RSS: the buttons for that are in the footer. Also, make sure to check my Training page.

The new framework

Since this is the last missing chapter, I’ll grab my last chance to describe some code from a top-down perspective. Instead of starting from the basic framework components and work my way up to higher-level classes, I’ll just show you what a completed finite-difference engine looks like in the new framework. It’s the FdBlackScholesVanillaEngine class; its declaration and the implementation of its calculate method are shown in the listing below.

class FdBlackScholesVanillaEngine
    : public DividendVanillaOption::engine {
  public:
    FdBlackScholesVanillaEngine(
        const shared_ptr<GeneralizedBlackScholesProcess>&,
        Size tGrid=100, Size xGrid=100, Size dampingSteps=0,
        const FdmSchemeDesc& schemeDesc=FdmSchemeDesc::Douglas(),
        bool localVol=false,
        Real illegalLocalVolOverwrite=-Null<Real>());

    void calculate() const;
  private:
    // data members, not shown
};

void FdBlackScholesVanillaEngine::calculate() const {
    shared_ptr<StrikedTypePayoff> payoff =
        dynamic_pointer_cast<StrikedTypePayoff>(
                                          arguments_.payoff);
    Time maturity = process_->time(
                               arguments_.exercise->lastDate());
    shared_ptr<Fdm1dMesher> equityMesher(
        new FdmBlackScholesMesher(
                xGrid_, process_, maturity, payoff->strike(),
                Null<Real>(), Null<Real>(), 0.0001, 1.5,
                std::pair<Real, Real>(payoff->strike(), 0.1)));

    shared_ptr<FdmMesher> mesher(
        new FdmMesherComposite(equityMesher));

    shared_ptr<FdmInnerValueCalculator> calculator(
                       new FdmLogInnerValue(payoff, mesher, 0));

    shared_ptr<FdmStepConditionComposite> conditions =
        FdmStepConditionComposite::vanillaComposite(
                      arguments_.cashFlow, arguments_.exercise,
                      mesher, calculator,
                      process_->riskFreeRate()->referenceDate(),
                      process_->riskFreeRate()->dayCounter());

    FdmBoundaryConditionSet boundaries;

    FdmSolverDesc solverDesc = {
        mesher, boundaries, conditions, calculator,
        maturity, tGrid_, dampingSteps_
    };
    shared_ptr<FdmBlackScholesSolver> solver(
        new FdmBlackScholesSolver(
               Handle<GeneralizedBlackScholesProcess>(process_),
               payoff->strike(), solverDesc, schemeDesc_,
               localVol_, illegalLocalVolOverwrite_));

    Real spot = process_->x0();
    results_.value = solver->valueAt(spot);
    results_.delta = solver->deltaAt(spot);
    results_.gamma = solver->gammaAt(spot);
    results_.theta = solver->thetaAt(spot);
}

The difference from, say, the FDAmericanEngine class from the old framework is straightforward enough. Instead of inheriting functionality from base classes, the new-style engine performs its required calculations by coordinating a number of components (such as meshers and calculators and conditions, oh my) that, at least in principle, can be reused by other engines. In the next posts in this series, I’ll examine them to see how they work and interact.