Jupyter notebook Assignment 2: Dual Methods/Dual Methods for American Options.ipynb
I. Parametric vs non-parametric regression
Let us define the random variables and by where is independent of X
Non-parametric regression
Plotting non-parametric regressions of with respect to with different values of the bandwidth:
Multiple regression
Questions on regression methods
1. Perform the piecewise linear regression of with respect to , where and are the random variables defined earlier, using a multidimensional regression of onto the order-1 basis functions , and plot the results.
2. Experiment with
various kernel functions, bandwidth values, and sample sizes (non-parametric regression),
with various sample sizes and number of basis functions (piecewise linear regression). Compare and comment the results.
3. Bonus question: Experiment with second-order Tikhonov regularization.
The second derivative of a piecewise-linear function being a Dirac comb. The penalization should be the sum of the squares of the weights of those Dirac masses.
II. American Option Pricing: The American Put in the Black-Scholes model
Simulation of a few path of geometric Brownian motion
Tsitsiklis-van Roy algorithm
We provide a simplistic implementation of the TVR algorithm.
The price from the backward induction from TVR is generally too high because regression errors accumulate in a positive fashion.
1. Experiment with various values of interest rates. Comment on the dependence of the American Put price on interest rate.
2. Adapt the TVR code to use the piecewise linear regression method implemented for the previous section.
3. For each discretization date, compute the exercise boundary. Draw a plot of the exercise boundary as a function of the date.
The exercise frontier is increasing and converges to the strike at maturity. The irregularity of the exercise frontier is due to regression errors varying between time steps.
4. Perform an independent Monte Carlo simulation using this exercise boundary as an exercise policy, and estimate the price of the American put. Explain why this estimate is a lower bound.
This is a lower bound of the price based on the approximation of the exercise frontier
Lonstaff-Schwartz Algorithm
We provide a simplistic implementation of the LS algorithm.
As expected the scatter plot has more variance in the case of the Longstaff-Schwartz algorithm.
Dual methods for American option pricing
Extracting the Martingale part of the snell envelope:
the martingale increments are equal to .
the conditional expectation in this term can decomposed in two parts, with the indicators of
,
, We have, , so that .
The benefit of this transformation is that estimating the conditional expectation is only required in , ie. in the exercise region. Bellow, we propose a first implementation of the dual method.
Assignment II
Provide an annotated version of the Longstaff-Schwartz algorithm and the dual method implemented in earlier cells.
Use a markdown cell with code areas to interleave code and detailed comments.
How does this differ from the classical Andersen-Broadie algorithm described in the attached pdf?
Reusing the exercise policy computed with the Longstaff-Schwartz algorithm, provide an implementation of the dual Andersen-Broadie method for the ATM American Put.
LONGSTAFF-SCHWARTZ ALGORITHM
We evaluate the expression , that is,
if this expression is true, we set, in all cases: In other words, if the value of exercise is higher, we choose to exercise.
If that expression is not true, then we do:
TVR:
LS:
It is said that TVR and LS have similar accuracy, but that LS will tend to produce less error.
We know that value of an option at maturity is the exercise value, or For example, we define maturity as T, where 1>t>n. We say . , the value at exercise.
We then want to evaluate the value at n-1. If is true, then we set , that is, we exercise the option and the options value becomes the value of exercise. If this is not true, then, under TVR, we would have , that is, we use the continuation value we have calculated. Under LS, we simply use the last value of the option that we have calculated: . Since we have calculated the value at maturity, then we say that the value at n-1 is equal to value at maturity, and we continue to loop through to find the value of n-2. We are then looking for a case where the value of continuation is greater than the value of exercise.
First we generate
tau is the current estimation of the index of the stopping time assuming that we have not exercised so far. By default it is a vector of ones (indicating that the stopping time it t=1). We multiply by nb_step to put this in "step order" eg the final time is nb_step, since we will later be indexing with i from 1 to nb_step. At the last date, it is equal to the last date index.
We generate a mesh, and an empty matrix of exercise frontiers to be filled in, as well as regressions on the mesh:
Backward induction
find the discount factors and find the payoff at exercise for each BS path, starting at the end (at T, and working backwards)
We see the exercise payoff is redefined for each time step t(i).
if i=0, then we have reached time=0 (eg the purchase date of the option). Thus, if i !=0, we compute continuation of the option by running a regression between path[i] and discount * price, where path[i] is a series of BS paths at time i, and price is the final payoff of those BS Paths initially, but changes as we loop through. Otherwise (we have run backwards to the purchase of the option) we would not exercise the option at t=0, so we compute the value of continuation, and we can just use the price vector that we computed earlier and find the mean of it.
Next we append the continuation mesh computed from the above if statement (that is, the mesh from the regression of the general mesh (which is a vector or stock prices from 70 to 130)) of the path[i] on discount * price(i) where I emphasize that price is a function of i. THat is, it is the regression of path[i] (X) with discount * price (Y) with the estimated values of Y at points on mesh.
Regressions is initially empty, but becomes a matrix of continuation_mesh appended for each i.
Frontiers is initially empty, but it is appended with: we take exercise_mesh (which does not vary with t, it is simply the payoff of a vector which spans 70-130, eg, it is max(0,K-mesh) we have continuation_mesh from the previous steps, which is the value of continuation of each of the BS paths at time i we find exercise_mesh > continuation_mesh, which will be a vector of ones or zeros, namely ones if the value of exercise is greater than the value of continuation. We append the MOST Recent vector of 1's and 0's (that is exercise_mesh < continuation_mesh[i]) to frontiers. We then generate a vector (exercise_now) where 1 indicates that exercising now is preferable, and 0 indicates that exercising later is preferable. We do this by taking exercise(i) > continuation(i) where I have emphasized that both vectors are specific to each timestep i. Next, we use the where function, where the first argument it condition. If condition =true (eg nonzero) then tau = x, and if condition =false(0) then tau=y (keeping in mind we are comparing vectors, so tau is a vector. Eg, if exercise_now=1, then tau=i. Otherwise, tau=tau (for index=1, the initial tau if a vector of 1's nb_step. Hence, by default, the stopping times are the maturity, but as we loop through, many of those values will be overwritten with earlier times). Then, we use the same where function, such that if exercise_now=1, then price=exercise, otherwise price=discount * price. We keep in mind that price is initially set as the payoff of the final value of all paths, but will gradually be changed as we loop over and over. Even if we do not exercise, we discount the price through each nb_step.
Then we plot the results, but only when i is the rounded integer value of nb_step/2 (or about halfway through all the values we loop over). We plot discount * price, exercise, and continuation.
We have exited the for loop
In this step, we mirror frontiers and regressions (e.g., if frontiers = [1 2 3] then frontiers[::-1]=[3 2 1], because we want them to now be in order. Next, we append K (the strike, which in this example is 100) to frontiers (which was previously flipped), since at maturity, the strike K is obviously the boundary of exercise.
And we print the price, which is the mean of the price vector (of all the BS paths) after the loop has finished
Dual methods for American option pricing
Generating a new Monte Carlo sample and computing the Snell envelope at the corresponding values
Generate a series of Black-Scholes paths
We initialize an empty snell envelope matrix that is the shape of path (nb_step x large_nb_mc). Then define the matrix disc as a vector of e^-rt where 0 < t < T (the discount factor), and that has another dimension.
We step through i (from i=1:nb_step). We compute, for each i, a value for the snell envelope that is the maximum of (the payoff of the black-scholes path at time i, and the piecewise linear interpolant of mesh(X) regressed with regression[i] (Y) at the points of path[i]). If payoff(path[i]) is greater, then this forms the Snell Envelope; otherwise, the envelope is comprised of the interpolated values of regressions[i] at the points path[i]. Keep in mind, regressions is related to the mesh of continuation values.
We then EXIT the FOR loop. We say that the snell envelope, at maturity, is the payoff of the paths at maturity (that is, max(0, K-S))
We then discount the Snell envelope
We plot the Snell envelope at different times (at maturity, at time 10 (halfway through), and at initial purchase)
Extracting the Martingale part of the snell envelope:
the martingale increments are equal to .
the conditional expectation in this term can decomposed in two parts, with the indicators of
,
, We have, , so that .
The benefit of this transformation is that estimating the conditional expectation is only required in , ie. in the exercise region. Bellow, we propose a first implementation of the dual method.
Extracting the Martingale part of Doob-Meyer decomposition of the Snell envelope.
Define mart as an empty matrix with dimensions of the path matrix:
The martingale starts from zero.
We define the first entry of the martingale matrix as 0:
We then step through and compute the exercise region at each date. We determine weather we should exercise by regressing mesh(X) with regressions[i] (Y, as we step through with i from 1 to nb_step). We then compare this estimated value of regression[i] with the payoff at path[i]. If the regressed value is less than the payoff of exercise, should_exercise is set to 1, otherwise it is 0.
Compute the martingale increments /
We initialize the martingale_increment matrix with 0s. We run a loop through the number of values in large_nb_mc If should_exercise == true/1 we generate a Black-Scholes paths near that increment assuming i is not at the end of nb_step, we say the conditional expectation is the mean of the maximum of the piecewise linear regression of mesh (X) and regression [i+j] (Y) and the payoff of the BS paths that were just generated. if i is at the end of nb_step, the conditional expectration is the mean of the payoff of the small monte carlo sim only (there is no continuation).
We then discount the conditional expectations. We define the matringale increment at [j] to be the value of snell at [i+1][j] - the conditional expectation just computed.
If should_exercise[j] is false: we just say the martingale increment is the difference of the snell envelopes between i+1 and i
We then add the martingale increments to mart[i]
Use this martingale to evaluate the american option price
Take the mean of the max of 0 and the discounted payoff minus the mart matrix. This gives us the price.
The Longstaff-Schwartz algorithm only provides a lower bound value for the American Option, but not an upper bound value. The Andersen-Broadie algorithm replaces the value of the option with in the formula that gives the optimal martingale increments to estimate the optimal Martingale. is the value at time of the option that pays at time
File "<ipython-input-30-dc381f7ab38f>", line 61
p3asum += 1/nump3a * discount = np.exp(-r * T / tau[m]) * payoff(newpath3a[tau[m]])
^
SyntaxError: invalid syntax