Chapter 8, part 7 of n: the new finite-difference framework
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.