The easy way to price these is of course via Monte Carlo simulation; it is simple to implement and straightforward to accommodate any added contract bells and whistles. But MC is slow and it's tough to get good Greeks out of it. There is of course another way.

## Pricing TARF's the PDE way

*K*(usually set below the spot

*S*at the time of issue) and a leverage factor

*g*. At every fixing date the holder makes a profit of (

*S - K*) if

*S*is above

*K*and a loss of

*g (K - S)*is

*S*fixes below

*K*(per unit of notional)

*;*

**profits accrue towards the target (but losses do not)**.

So the structure is knocked out when/if the accrued amount

*A*reaches the target. This is a strong path dependency feature; but unlike accumulators where the knock out depends on the path of the spot itself (which is already part of the numerical solution), here we need to somehow involve

*A*in the solution. We do that by adding

*A*as an extra pseudo-dimension, discretized by a number of individual 1-D PDE solvers (for Black Scholes, local volatility (LV) model, or local regime switching). Each of these solvers corresponds to an

*A*-level within the range of possible values (from zero to the target).

Solving backwards from maturity, we march the option value in time separately for each solver until we reach a fixing/settlement date (for simplicity here I assume that fixing and settlement dates coincide). There we have a jump condition that must be applied in order to continue solving. More specifically, for each

*S*-grid point on each solver we determine the payment to be made based on the

*S*value and the solver's

*A*level. Adding positive payments to the solver's

*A*, gives us the implied

*A*level that corresponds to each

*S*grid point of the solver just after (in normal time direction) the payment has been made. Given the implied

*A*level we can find the option value there by interpolating from the solutions of the solvers whose

*A*levels are nearest (which we have all marched up to that time point). We do that with say cubic interpolation. The (initial, or rather final) values with which we start solving again towards the next fixing date are then found by adding the payout to the interpolated continuation value.

That is the outline (by the way, this "auxiliary state variable" method can be seen in action when pricing Asian options within the old option pricer in this site). I will stick with the basics here (no volatility model) in order to show that even in this simple setting the implementation leaves enough room for one to come up with a great, or not so great pricing engine.

So each individual solver is solving the Black Scholes pricing PDE using the Crank Nicolson method with Rannacher time-stepping on a non-uniform

*S*-grid that places more points near the strike. This standard building block is well-optimized and one can use it as per above to put together a basic implementation of the TARF pricing engine. I did this and the results while still better than MC, left a lot to be desired in my view. Let's just say that a basic implementation results in a solution that does not behave optimally (and a lot worse than it does for Asian options by the way). So I tried to find ways to improve things. And here I will just give an indication of how much one can improve. The details that make this possible will not be the subject of this short post, but if one really wants to know you can contact me (using the contact form or the email in this paper).

## Test cases

*S*-grid, boundary conditions, etc) in both engine implementations. I was aiming for an accuracy of about $ 10^{-4} $ and the time discretization error was smaller than that when

*NT*= 500 time steps were used. I played a bit with the

*S*resolution (

*NS)*to this end. The spacing between the the

*A*(

*S-t*) planes was roughly the same as the average

*S*-grid spacing in both implementations (though uniform for the basic and non-uniform for the optimized). Note that there are generally three ways of handling the settlement of the fixing that results in the target being reached, i.e. three knockout types. a)

*No pay*: payment is not made, b)

*Capped pay*there is partial payment so as to "fill" the target exactly, c)

**:***Full pay*: payment is made in full. All three are of course trivially accommodated by the method.

The plots below show the numerical (spatial discretization) error for the part of the solution that is of interest (the actual solver S-grid extends further) and assuming the accrued amount today is zero, i.e.

*A*= 0. This may mean we are pricing at the time of issue, or at some time during the lifetime of the contract (in which case target stands for "remaining target"). The error profile is obtained by comparing the solution to that from an optimized engine using

*NS*= 6000 and

*NT*= 500 (this has really, really low spatial discretization error, < $10^{-8}$ to be precise). One CPU (Ryzen 5900X) core was used for the timings shown, though if need be the method is easily parallelized. Code is written in C++ and compiled with gcc on Linux. Interest rates are zero.

First we look at a one year contract with weekly fixings/payments and volatility typical of many FX rates. The knockout type is

*n*

*and the leverage factor is two. The optimized version achieves the desired accuracy in 0.09 seconds, while the basic version needs a lot higher spatial resolution and 5 seconds to come close to that.*

*o*pay*ull pay*and the leverage factor is one. In this setting the optimized engine's relative advantage is more pronounced, achieving the desired level of accuracy in 0.06 seconds while the basic engine really struggles here and fails to come close even with a spatial resolution ten times higher. The keen observer will notice the basic problem here immediately.

By the way, if the aim is a single spot valuation, it is often (but not always) preferable to cluster the grid points around the current spot (typical for example when one solves the PDE in log space). In this case one can get higher efficiency still, i.e. same discretization error in even less CPU time.

## Some benchmark valuations

*dt = 1/52*yrs apart (say forcing an ACT/364 day count with no holidays affecting the weekly fixings dates), flattening the volatility surface and zeroing rates curves, should reproduce the values below.

**Table 1.**Benchmark valuations for a bullish Target Redemption Accrual Forward (TARF) under Black Scholes. In all cases the strike K = 1 and both domestic and foreign rates are zero. The values were obtained with a highly optimized PDE-based pricing engine and all digits shown should be converged, except the last one which may be off by 1 or 2 points.

Case | T (yrs) | num. fixings | target | lev. factor | KO type | spot | BS vol | TARF value |

1 | 1 | 52 | 0.3 | 2 | No Pay | 1.06 | 10% | -0.02096094 |

2 | 1 | 52 | 0.5 | 2 | No Pay | 1.06 | 10% | -0.017514630 |

3 | 1 | 52 | 0.7 | 2 | No Pay | 1.06 | 10% | 0.035902523 |

4 | 1 | 52 | 0.3 | 2 | No Pay | 1.1 | 10% | 0.235120763 |

5 | 1 | 52 | 0.3 | 2 | Capped pay | 1.1 | 10% | 0.286424762 |

6 | 1 | 52 | 0.3 | 2 | Full pay | 1.1 | 10% | 0.335294058 |

7 | 1 | 52 | 0.3 | 1 | No Pay | 1.03 | 10% | -0.29368756 |

8 | 1 | 52 | 0.3 | 1 | No pay | 1.1 | 20% | -0.01224772 |

9 | 1 | 52 | 0.7 | 1 | No pay | 1.1 | 20% | 0.037345388 |

10 | 1 | 52 | 0.7 | 1 | Full pay | 1.1 | 20% | 0.152792822 |

11 | 2 | 104 | 0.3 | 1 | No pay | 1.35 | 40% | 0.059232579 |

12 | 2 | 104 | 0.5 | 1 | No pay | 1.35 | 40% | 0.315294774 |

13 | 2 | 104 | 0.5 | 1 | Full pay | 1.1 | 40% | -3.81704655 |