# Chapter 8, part 11: Black-Scholes finite-difference operators

Greetings.

This week, another post in a series on the new finite-difference framework. The end of the chapter doesn’t look so far away, now. And if you missed the series so far, the first post is here.

In other news, I’m just back from the QuantLib User Meeting in Düsseldorf. I’ll try to write a trip report shortly; in the meantime, you can check the QuantLib Twitter feed for pictures and a few links.

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.

### Examples: Black-Scholes operators

Most full-featured operators in the library are not inherited directly
from the `FdmLinearOp`

class or from one of the basic operators.
Instead, they inherit from the `FdLinearOpComposite`

class (shown
in the listing below), contain one or more basic
operators as data members, and use them to implement their own
behavior.

As you can see, the `FdmLinearOpComposite`

class augments the
interface of operators with a few more methods that derived classes
must implement, the simplest being `size`

(which must return the
number of dimensions of the operator).

The other methods deserve a bit more attention. The `setTime`

method
implements the same idea I described in a previous post: when called, it
should modify or rebuild a time-dependent operator so that its
elements correspond to the correct time. However, there are a couple
of enhancements. First, in the old framework the machinery was added
to the `TridiagonalOperator`

class, that is, to the basic building
block for operators; in the new one, basic operators are constant (and
simpler) and the `setTime`

method was added to a higher-level
interface. Second, the operator will be used over a given step, and
this interface allows one to pass both its start and end time; this
allows operators to provide a better discretization (for instance, by
averaging or integrating) than simply the value at a single time.

The remaining methods are used to support Alternating Direction
Implicit (ADI) schemes. I’m not going to describe them in any detail
here (a summary is available, e.g., in [1], and you all know how to
use Google anyway); the basic idea is that an operator \( A \) is
decomposed as \( A = A_m + A_0 + A_1 + \ldots + A_{N-1} \), where \( A_m \)
represents the mixed derivatives and each \( A_i \) represents the
derivatives along the \( i \)-th direction, and those components are used
separately. Instead of having the operator create the actual
components and let the schemes apply them, the interface declares
corresponding methods: thus, the `apply_mixed`

method will apply the
\( A_m \) component and the `apply_direction`

method will apply one of the
\( A_i \) depending on the direction passed to the method. The
`solve_splitting`

and `preconditioner`

methods are also used in ADI
schemes.

As a first example, you can look at the `FdmBlackScholesOp`

class, shown in the next listing.

As expected, it inherits
from `FdmLinearOpComposite`

and implements its required
interface. The constructor takes quite a few parameters and stores
them in the corresponding data members for later use; among them, it
takes a given direction, which let us specify the axis along which
this operator works and thus allows it to be used as a building block
in other operators.

The underlying differential operator, stored in the `mapT_`

data
member, is built inside the `setTime`

method. As I mentioned,
having both the start time `t1`

and the end time `t2`

of the
step allows the code to provide a more accurate discretization;
namely, it can ask the term structures for the exact forward rates and
variance between those two times instead of picking an instantaneous
value. Depending on whether we want to use local volatility, the
calculation of the diffusion term differs; but in both cases we end up
building the Black-Scholes operator

and storing it into `mapT_`

so that it can be used elsewhere.

Once the final operator is built, the implementation of the remaining
methods is straightforward enough. The `apply`

method applies
`mapT_`

to the passed array and return the results. Since this
is a one-dimensional operator, there are no cross-terms, therefore
`apply_mixed`

returns a null array. Finally, the
`apply_direction`

method applies `mapT_`

to the passed array
when the direction equals the one specified in the constructor
(because that’s the one direction along which the entire operator
works) and instead returns a null array when the direction is
different (because the operator has no corresponding component).
The implementations of the other methods work in a similar way.

As a second example, the `Fdm2dBlackScholesOp`

class, shown in
the listing below, builds a two-dimensional Black-Scholes
operator by combining a pair of one-dimensional operators with their
correlation.

Again, the constructor stores the passed data, while the
`setTime`

method builds the operators; directly in the case of
the correlation `corrMapT_`

, and forwarding to the corresponding
methods in the case of the two one-dimensional operators `opX_`

and `opY_`

.

The other methods are, again, simple. By linearity of the operators,
the `apply`

method works by applying each component to the passed
array in turn and returning the sum of the results; `apply_mixed`

uses the mixed operator `corrMapT_`

plus a constant term; and
`apply_direction`

selects and applies the correct one-dimensional
component.

If you’re interested, the library provides other operators you can
examine. Most of them turn out to have the same structure: for
instance, the `FdmHestonOp`

class, which implements a helper
operator for each underlying variable and puts them together in the
final operator, or the `FdmHestonHullWhiteOp`

, that you can
inspect as an example of three-dimensional operator.

#### Bibliography

[1] C. S. L. de Graaf. *Finite Difference Methods in Derivatives
Pricing under Stochastic Volatility
Models*. Master’s
thesis, Mathematisch Instituut, Universiteit Leiden, 2012.