In this chapter we introduce methods to price some of the more popular exotic options, including single-barrier options, Asian options, lookback options, and cash-or-nothing and asset-or-nothing options. We emphasize barrier options since these options have become very popular and can be difficult to price, especially when the barrier is close to the spot price of the asset. This is especially true when using tree-based methods, because the barrier rarely corresponds to any of the price nodes on the tree. All the methods covered in this chapter present novel ways to deal with this difficulty. We show that all the methods produce good approximations to the analytic barrier price. Many European barrier options are available in closed form. See Haug (1998) for a thorough treatment of these options.
Single-barrier options are classified as either knock-in or knock-out options. Knock-in options become activated only if the asset price reaches a barrier, while knock-out options become worthless once the barrier is reached. Down-and-in (DI) options become active if the stock price drops below a lower boundary, and up-and-in (UI) options becomes active of the stock price rises above an upper boundary. Down-and-out (DO) options and up-and-out (UO) options work the same way, except that they become worthless once the barrier is reached. For European options, a simple barrier parity relationship exists, according to which the price of a knock-in option plus the price of a knock-out option equals the price of a plain-vanilla option. Hence, for European single barrier calls and puts,
These parity relationships are intuitive, by considering, for example, a portfolio comprised of a single DI option and a single DO option with similar strike and maturity. If the asset price does not reach the barrier, the DO option stays active and the DI option stays worthless. Conversely, if the asset price reaches the barrier, the DO option becomes worthless and the DI option comes into existence. In either case, the portfolio retains the right to exercise the option at the strike price, exactly as if a plain-vanilla option were being held. A similar argument holds for a portfolio comprised of a single UI and a single UO option. We obtain the price of European up-and-in and down-and-in options by first obtaining the prices of their up-and-out and down-and-out counterparts, and then applying this relation. Unfortunately, (8.1) does not hold for American barrier options.
To price American options, we use the reflection principle described by Haug (2001), according to which the price of a down-and-in American call can be expressed as
where S is the spot price, K is the strike price, H is the barrier (H < S), T is the time to maturity, r is the risk-free rate, and σ is the volatility of the underlying, and is the price of an American plain-vanilla call option, obtained by using methods described in Chapter 3, for example. Similarly, the price of an up-and-in American put is
Kwok and Dai (2004) show that (8.2) holds when only, and that (8.3) holds when
only. In this chapter we present VBA functions for implementing their method, which holds for American down-and-in calls and up-and-in puts under more general conditions.
Pricing barrier options with tree-based methods may seem easy, since at first glance all that is needed is a slight modification that sets the option price to zero when the barrier is reached. However, it is well known that tree-based methods have trouble converging because the generated asset prices rarely lie on the barrier. The models we present all propose novel methods to deal with this difficulty.
The price of a barrier option depends on how often the barrier is monitored. Many barrier option pricing formulas assume continuous monitoring, however, which implies that the asset price must be constantly monitored to verify whether it has crossed the barrier. Since continuous monitoring is not feasible, monitoring is done at discrete time intervals. For example, a knock-out option monitored daily will be knocked out only if the closing price of the asset reaches the barrier, even though the asset may have reached the barrier during the trading day. Broadie, Glasserman, and Kou (1997, 1999) have proposed an approximation to correct for discrete barrier monitoring. If f(H) denotes the price of a continuous knock-in or knock-out down call or up put with barrier H, then the price fm(H) of the corresponding discretely monitored option is
where “+” in the exponent is used for up options (when H > S), and “−” is used for down options (when H < S), and where β ≈ 0.5826. There are two ways to specify monitoring. The first is to specify m, the number of times the barrier will be monitored during the life of the option, T. For example, if the option has a time to maturity of three months (0.25 years) and the barrier is to be monitored five times over the life of the option, then appears in the exponent to (8.4). The second is to specify the frequency of monitoring, usually hourly, daily, weekly, or monthly. For example, with monthly monitoring
appears in the exponent. Hence, adjusting for discrete monitoring in a barrier option pricing formula is straightforward with the approximation (8.4), because H is simply replaced by
everywhere H is encountered in the formula.
The VBA function NewBarrier() is used to adjust the barrier for discrete monitoring. It creates a new barrier based on (8.4) under either monitoring method. If the parameter M1 is set to zero, the second method is used with frequency specified by the parameter M2. Otherwise, the first method is used, with number of monitoring times specified by the value of M1. This barrier adjustment is constructed with 365 days per year.
Function NewBarrier(Spot, Bar, T, v, M1, M2 As String)
If Bar > Spot Then
Sign = 1
Else
Sign = -1
End If
Select Case M1
Case Is <> 0
Bar = Bar * Exp(Sign * 0.5826 * v * Sqr(T / M1)
Case Is = 0
Select Case M2
Case “H”: Bar = Bar * Exp(Sign * 0.5826 * v * Sqr(1 / 24 / 365)
Case “D”: Bar = Bar * Exp(Sign * 0.5826 * v * Sqr(1 / 365)
Case “W”: Bar = Bar * Exp(Sign * 0.5826 * v * Sqr(1 / 52)
Case “M”: Bar = Bar * Exp(Sign * 0.5826 * v * Sqr(1 / 12)
End Select
End Select
NewBarrier = Bar
End Function
The flexible tree of Tian (1999) covered in Chapter 3 can easily be modified to price barrier options. In this section we explain how to construct the flexible binomial tree for European single-barrier options when there is continuous monitoring. This requires that a two-stage tree be constructed. The first part of the tree is a flexible binomial tree, tilted so that one of its nodes lies exactly on the barrier. The remaining part of the tree is a CRR binomial tree, corresponding to a flexible tree with a tilt parameter of zero. Since the CRR recombines, in the second part of the flexible tree the barrier will always lie on the tree nodes.
Recall that the parameters of the flexible binomial tree are given by
and that the CRR binomial tree parameters u0, d0, and p0 are obtained by setting λ = 0 in u, d, and p, respectively, in (8.5). Using techniques similar to those outlined in Chapter 3 for the flexible tree of Tian (1999), the tilt parameter can be derived as
where
where H is the barrier, and where int[] denotes rounding to the nearest integer. As shown by Tian (1999), the first stage of the tree has asset prices given as , while the second stage of the tree, as
(i > N0). The two-stage flexible binomial tree constructed in this fashion has recombining nodes throughout, and the barrier is reached after exactly N0 steps.
To implement the two-stage flexible binomial tree for European single barrier options, we obtain the prices of down-and-out and up-and-out calls and puts directly. To obtain the prices of down-and-in and up-and-in options, we use the parity relation (8.1), along with plain-vanilla prices obtained using the CRR binomial tree. The Excel file Chapter8FBBarrierC contains the VBA function FBBarrierC() to implement the Tian (1999) two-stage flexible binomial tree for single barrier European options. Note that this requires a slight modification of the notation, to reflect the different indexing for pairs (i, j). In Tian (1999) the first index represents time and the second index represents the nodes, but this is reversed in the VBA coding. For example, in the function FBBarrierC() the first stage has asset prices given by
, while the second stage has asset prices given by
. This is achieved in the first part of the FBBarrierC() function.
Function FBBarrierC(Spot, K, H, T, r, sigma, n, OpType As String, PutCall As String)
dt = T / n: u0 = Exp(sigma * Sqr(dt): d0 = 1 / u0
p0 = (Exp(r * dt) - d0) / (u0 - d0)
N0 = Round(Log(H / Spot) / Log(d0)
L = (Log(H / Spot) + N0 * sigma * Sqr(dt) / N0 / sigma ^ 2 / dt
u = Exp(sigma * Sqr(dt) + L * sigma ^ 2 * dt)
d = Exp(-sigma * Sqr(dt) + L * sigma ^ 2 * dt)
p = (Exp(r * dt) - d) / (u - d)
Dim S() As Double, Op() As Double
ReDim S(n + 1, n + 1) As Double, Op(n + 1, n + 1) As Double
S(1, 1) = Spot
For j = 1 To n + 1
For i = 1 To j
If j <= N0 + 1 Then
S(i, j) = S(1, 1) * u ^ (j - i) * d ^ (i - 1)
Else
S(i, j) = S(1, 1) * d ^ (N0) * u0 ^ (j - i) * d0 ^ (i - N0 - 1)
End If
S(i, j) = Round(S(i, j) * 10000, 5) / 10000
Next i
Next j
The second part of the function calculates terminal option prices and verifies whether the asset prices lie above or below the barrier.
For i = 1 To n + 1
If (S(i, n + 1) <= H And (OpType = “DI” Or OpType = “DO”) Or (S(i, n + 1) >= H And (OpType = “UI” Or OpType = “UO”) Then
Op(i, n + 1) = 0
Else
Select Case PutCall
Case “Call”
Op(i, n + 1) = Application.Max(S(i, n + 1) - K, 0)
Case “Put”
Op(i, n + 1) = Application.Max(K - S(i, n + 1), 0)
End Select
End If
Next i
The next part of the function computes the option price by backward induction, again verifying where the asset prices lie relative to the barrier. Note that the second stage uses the CRR probability p0, while the first stage uses the probability p from (8.5).
For j = n To 1 Step -1
For i = 1 To j
If (S(i, j) <= H And (OpType = “DI” Or OpType = “DO”) Or
(S(i, j) >= H And (OpType = “UI” Or OpType = “UO”)
Then
Op(i, j) = 0
Else
If j <= N0 Then
Prob = p
Else
Prob = p0
End If
Op(i, j) = Exp(-r * dt) * (Prob * Op(i, j + 1)
+ (1 - Prob) * Op(i + 1, j + 1)
End If
Next i
Next j
Finally, the last part of the function calculates the option prices and applies the parity relation (8.1) if needed.
If OpType = “DO” Or OpType = “UO” Then
FBBarrierC = Op(1, 1)
Else
FBBarrierC = Binomial(Spot, K, T, r, sigma, n, PutCall) - Op(1, 1)
End If
End Function
This function is illustrated in Figure 8.1, using the same parameter values that were used to generate Table IV of Tian (1999)
FIGURE 8.1 Two-Stage Flexible Binomial Tree
The cells in column C have been named for convenience. To obtain the price of the barrier option with the given parameters, in cell C16 we type
which produces a price of 5.7168. Using the same parameter values, the price of a down-and-in call is 2.5596, close to the analytical value of 2.5615 (see Haug, 1998).
If the CRR binomial tree is used to price barrier options, by setting the option price to zero whenever the barrier is reached, convergence to the true price will be very slow and follow a sawtooth pattern. The error will be small for those values of n that generate asset prices that fall close to the barrier, but will be large when asset prices lie far from the barrier. Hence, using a large number of steps does not necessarily ensure fast converge. Recognizing this, Boyle and Lau (1994) propose to restrict the number of steps in the tree to those values that generate asset prices close to the barrier. They suggest using a value of n that is the largest integer that is smaller than F(m), where
for m = 1, 2, 3 ... .
The Excel file Chapter8BarrierBin contains the VBA function BarrierBin() for implementing the Boyle and Lau (1994) method. The function calculates the prices of knock-out options directly, and calculates the other types of options using the barrier parity relationship (8.1), or the reflection principles (8.2) and (8.3), in accordance with Table 8.1. It is not possible to obtain the prices of American up-and-in calls or American down-and-in puts with this tree.
TABLE 8.1 Pricing Barrier Options with Binomial Tree
The first part of the BarrierBin() function updates the barrier according to which type of monitoring is used, which ensures that the barrier lies below (above) the spot price for down-and-out and down-and-in (up-and-out and up-and-in) options. The closest optimal number of steps above the number specified as an input, n, is chosen using the function F(m). If n is not large enough, an error message appears that requests a larger value be used.
Function BarrierBin(Spot, Strike, Bar, T, r, v, old_n, PutCall As String, EuroAmer As String, BarType As String, M1, M2 As String)
Bar = NewBarrier(Spot, Bar, T, v, M1, M2)
If (BarType = “DO” Or BarType = “DI”) And Bar > Spot Then
MsgBox “Error: Barrier Must be Below Spot Price for a
Down-and-Out or Down-and-In Option”
ElseIf (BarType = “UO” Or BarType = “UI”) And Bar < Spot Then MsgBox
“Error: Barrier Must be Above Spot Price for a
Up-and-Out or Up-and-In Option”
Else
For m = 1 To 100
F(m) = m ^ 2 * v ^ 2 * T / (Log(Spot / Bar) ^ 2
Next m
If old_n < F(1) Then
MsgBox (“Increase Number Steps to at Least “ &
Application.Floor(F(1) + 1, 1)
Else
For i = 1 To 99
If (F(i) < old_n) And (old_n < F(i + 1) Then
n = Application.Floor(F(i + 1), 1)
Exit For
End If
Next i
End If
The second part of the function defines the CRR parameters, and constructs the option prices in exactly the same way as in Chapter 3, except that the option price is set to zero when the option crosses the barrier. To conserve space, only the part of the function that calculates European calls is presented.
dt = T / n: u = Exp(v * Sqr(dt)
d = 1 / u: p = (Exp(r * dt) - d) / (u - d)
exp_rT = Exp(-r * dt)
For i = 1 To n + 1
AssetPrice = Spot * u ^ (n + 1 - i) * d ^ (i - 1)
If ((BarType = “DO” Or BarType = “DI”)
And AssetPrice <= Bar) Or
((BarType = “UO” Or BarType = “UI”)
And AssetPrice >= Bar) Then
Op(i, n + 1) = 0
ElseIf PutCall = “Call” Then
Op(i, n + 1) = Application.Max(AssetPrice - Strike, 0)
End If
Next i
For j = n To 1 Step -1
For i = 1 To j
AssetPrice = Spot * u ^ (j - i) * d ^ (i - 1)
If ((BarType = “DO” Or BarType = “DI”)
And AssetPrice <= Bar) Or _
((BarType = “UO” Or BarType = “UI”)
And AssetPrice >= Bar) Then
Op(i, j) = 0
Else
Op(i, j) = exp_rT * (p * Op(i, j + 1)
+ (1 - p) * Op(i + 1, j + 1)
End If
Next i
Next j
In accordance with Table 8.1, the prices of down-and-out and up-and-out options are outputted directly. The prices of a European down-and-in or down-and-out call or put are obtained from the barrier parity relationship, where the plain-vanilla value is obtained from the CRR binomial through the VBA function fbinomial(). The prices of an American down-and-in call and up-and-in put are obtained using the reflection principle. Finally, since American down-and-in puts and up-and-in calls cannot be obtained with the algorithm, a message box appears if the user attempts to price these options.
If BarType = “DO” Or BarType = “UO” Then
output(1, 1) = Op(1, 1)
Else
Select Case EuroAmer
Case “Euro”
If PutCall = “Call” Then
output(1, 1) = fbinomial(Spot, Strike, r, v, T, n,
“Call”, “Euro”) - Op(1, 1)
ElseIf PutCall = “Put” Then
output(1, 1) = fbinomial(Spot, Strike, r, v, T, n,
“Put”, “Euro”) - Op(1, 1)
End If
Case “Amer”
If PutCall = “Call” And BarType = “DI” Then
output(1, 1) = (Spot / Bar) ^ (1 - 2 * r / v ^ 2)*
fbinomial(Bar ^ 2 / Spot, Strike, r, v, T, n,
“Call”, “Amer”)
ElseIf PutCall = “Put” And BarType = “UI” Then
output(1, 1) = (Spot / Bar) ^ (1 - 2 * r / v ^ 2)*
fbinomial(Bar ^ 2 / Spot, Strike, r, v, T, n,
“Put”,”Amer”)
ElseIf (PutCall = “Put” And BarType = “DI”) Then
MsgBox “You Cannot Price an American Down-and-In Put
Using This Algorithm”
ElseIf (PutCall = “Call” And BarType = “UI”) Then
MsgBox “You Cannot Price an American Up-and-In Call
Using This Algorithm”
End If
End Select
End If
output(2, 1) = n
BarrierBin = output
End Function
Figure 8.2 illustrates the BarrierBin() function on a down-and-in American call with strike price K = 140, barrier H = 95 and time to maturity T = 1 year, when the risk-free rate and volatility are r = 0.10 and σ = 0.25, respectively, and with n = 250 time steps. The barrier is H = 95 and monitored daily, so in cell C17 we put “D” and cell F8 we type
FIGURE 8.2 Boyle and Lau (1994) Binomial Pricing for Barrier Options
which produces an adjusted barrier value of 94.2785. To obtain the option price and the actual number of optimal steps produced by the Boyle and Lau (1994) method, in cell F6 we type
and copy to cell F7. The price of the option is $0.8156 and appears in cell F6, while the optimal number of time steps is n = 288 in cell F7. The price of a European down-and-in call is 0.8154. For comparison, the analytic value of the European down-and-in call is 0.8180 (see Haug, 1998)
Derman et al. (1995) propose an alternate method to price single barrier options. They note that while the specified barrier rarely lies on tree nodes, it always lies above and below the modified barrier and effective barrier, respectively (see their Figure 7). For UO and UI options, the effective barrier consists of asset prices immediately above the barrier, while the modified barrier consists of asset prices immediately below the barrier. Their approach is to interpolate option prices obtained at the modified and effective barriers, using a first order Taylor series expansion.
The Excel file Chapter8BarrierUp contains the VBA function BarrierUp() for pricing European up-and-in and up-and-out options, and for pricing American up-and-in puts using the reflection principle (8.3). The first part of the BarrierUp() function constructs the CRR binomial tree and stores the asset prices in the array S(). The second part creates “naïive” up-and-out option prices, namely, those obtained by using only the effective barrier, and stores them in the array Op(). These are obtained simply by setting the CRR asset prices to zero when they lie above the barrier.
Function BarrierUp(Spot, Strike, H, T, r, v, n, PutCall As String, EuroAmer As String, UpType As String, M1, M2 As String)
For i = 1 To n + 1
If S(i, n + 1) >= H Then
Op(i, n + 1) = 0
Else
Select Case PutCall
Case “Put”: Op(i, n + 1) = Application.Max(Strike
- S(i, n + 1), 0)
Case “Call”: Op(i, n + 1) = Application.Max(S(i, n + 1)
- Strike, 0)
End Select
End If
Next i
For j = n To 1 Step -1
For i = 1 To j
If S(i, j) >= H Then
Op(i, j) = 0
Else
Select Case EuroAmer
Case “Euro”:
Op(i, j) = exp_rT * (p * Op(i, j + 1)
+ (1 - p) * Op(i + 1, j + 1)
Case “Amer”:
If PutCall = “Call” Then
Op(i, j) = Application.Max(S(i, j) - Strike,
exp_rT * (p * Op(i, j + 1) + (1 - p)
* Op(i + 1, j + 1))
If PutCall = “Put” Then
Op(i, j) = Application.Max(Strike - S(i, j),
exp_rT * (p * Op(i, j + 1) + (1 - p)
* Op(i + 1, j + 1))
End Select
End If
Next i
Next j
The next part constructs the modified (lower) barrier and interpolates option prices. The array L() identifies which components of the tree contain the modified barrier.
' Modified (Lower) Barrier
Dim L() As Double
ReDim L(n + 1, n + 1) As Double
For j = 1 To n
If (S(1, j) <= H And H <= S(1, j + 1))
Or (H <= S(1, j + 1)) Then
L(1, j) = 1
End If
Next j
L(1, n + 1) = 1
For i = 2 To n + 1
For j = 2 To n + 1
If S(i - 1, j - 1) <= H And H <= S(i - 1, j) Then
For K = j To n + 1
L(i, K) = 1
Next K
End If
Next j
Next i
' Interpolate Option Prices at the Lower Barrier
For i = 2 To n
For j = i To n
If L(i, j) = 1 Then
d = S(i, j)
u = S(i - 1, j)
Op(i, j) = (H - d) / (u - d) * Op(i, j)
End If
Next j
Next i
The next step is to identify option prices that must be updated along the last column and along the rows of the array L(), and then apply backward recursion to the identified option prices.
For j = n To 1 Step -1
For i = 1 To j
If L(i, j) = 0 Then
Select Case EuroAmer
Case “Euro”:
Op(i, j) = exp_rT * (p * Op(i, j + 1) + (1 - p)
* Op(i + 1, j + 1)
Case “Amer”:
If PutCall = “Call” Then
Op(i, j) = Application.Max(S(i, j) - Strike,
exp_rT * (p * Op(i, j + 1) + (1 - p)
* Op(i + 1, j + 1))
If PutCall = “Put” Then
Op(i, j) = Application.Max(Strike - S(i, j),
exp_rT * (p * Op(i, j + 1) + (1 - p)
* Op(i + 1, j + 1))
End Select
End If
Next i
Next j
Finally, up-and-out options are stored in Op(1,1) and are outputted directly. The prices of up-and-in puts and calls are obtained by the parity relationship (8.1), and the price of American up-and-in puts are obtained using the reflection principle (8.3). The prices of plain-vanilla options are obtained using the CRR binomial tree and the VBA function Binomial(), stored in separate module within the Excel file Chapter8BarrierUp.
If UpType = “UO” Then
Price = Op(1, 1)
Else
Select Case EuroAmer
Case “Euro”
If PutCall = “Call” Then
Price = Binomial(Spot, Strike, T, r, v, n, “Call”, “Euro”) - Op(1, 1)
ElseIf PutCall = “Put” Then
Price = Binomial(Spot, Strike, T, r, v, n, “Put”, “Euro”) - Op(1, 1)
End If
Case “Amer”
If PutCall = “Put” And UpType = “UI” Then
Price = (Spot / H) ^ (1 - 2 * r / v ^ 2) * Binomial(
H ^ 2 / Spot, Strike, T, r, v, n, “Put”, “Amer”)
End If
End Select
End If
BarrierUp = Price
End Function
Figure 8.3 illustrates the BarrierUp() function for a European up-and-in put, using n = 500 steps. In cell F6 we type
FIGURE 8.3 Interpolated Price for a European Up-and-In Put
which produces a price of $7.8160. The exact price of this option is $7.8154 (see Haug, 1998). The price of an American up-and-in put with the same parameter values is $8.0702
The method of Derman et al. (1995) can also be used for “down” options. Exactly the same methodology is applied, except that the interpolation scheme reflects the fact that the effective barrier now lies below the specified barrier, while the modified barrier lies above.
The Excel file Chapter8BarrierDown contains the VBA function BarrierDown() for implementing European down-and-out options, and American down-and-in calls. The function is similar to the BarrierUp() function described above, so only selected parts of the BarrierDown() function are presented. The “naïive” down-and-out prices are obtained in a similar fashion, except the option prices are set to zero when CRR asset prices lie at or below the barrier.
Function BarrierDown(Spot, Strike, H, T, r, v, n, PutCall As String, EuroAmer As String, UpType As String, M1, M2 As String)
For i = 1 To n + 1
If S(i, n + 1) <= H Then
Op(i, n + 1) = 0
Else
Select Case PutCall
Case “Call”: Op(i, n + 1) = Application.Max(S(i, n + 1)
- Strike, 0)
Case “Put”: Op(i, n + 1) = Application.Max(Strike
- S(i, n + 1), 0)
End Select
End If
Next i
The other option prices are obtained by the usual method of backward recursion, but the option prices are set to zero when the asset prices fall below the barrier. The next part creates the modified barrier and interpolates option prices between the effective and modified barriers.
' Modified Barrier
For j = 1 To n
For i = 1 To j
If S(i + 1, j) <= H And H <= S(i, j)
And S(i + 1, j) <> 0 Then
L(i, j) = 1
L(i + 1, j) = 1
End If
Next i
Next j
' Interpolate Option Values
For j = 1 To n
For i = 1 To j
If L(i, j) = 1 And L(i + 1, j) = 1 Then
Up = S(i, j)
Down = S(i + 1, j)
Op(i, j) = (H - Up) / (Down - Up) * Op(i, j)
End If
Next i
Next j
' Identify Which Option Prices to Update
' Last Column
For i = 1 To n + 1
L(i, n + 1) = 1
Next i
' Impute First Barrier Value and Values Below the Barrier
For j = 2 To n
For i = 1 To j
If L(i, j) = 1 And L(i + 1, j) = 1 Then
L(i, j - 1) = 1
For k = 1 To n - i + 1
L(i + k, j) = 1
Next k
End If
Next i
Next j
Down-and-out option prices are obtained directly from Op(1,1), European down-and-in options from the parity relationship (8.1), and American down-and-in calls from the reflection principle (8.2).
' Final Pass of Backward Induction on Option Prices
For j = n To 1 Step -1
For i = 1 To j
If L(i, j) = 0 Then
Select Case EuroAmer
Case “Euro”:
Op(i, j) = exp_rT * (p * Op(i, j + 1) + (1 - p)
* Op(i + 1, j + 1)
Case “Amer”:
If PutCall = “Call” Then
Op(i, j) = Application.Max(S(i, j) - Strike,
exp_rT * (p * Op(i, j + 1) + (1 - p)
* Op(i + 1, j + 1))
If PutCall = “Put” Then
Op(i, j) = Application.Max(Strike - S(i, j),
exp_rT * (p * Op(i, j + 1) + (1 - p)
* Op(i + 1, j + 1))
End Select
End If
Next i
Next j
If UpType = “DO” Then
Price = Op(1, 1)
Else
Select Case EuroAmer
Case “Euro”
If PutCall = “Call” Then
Price = Binomial(Spot, Strike, T, r, v, n, “Call”, “Euro”) - Op(1, 1)
ElseIf PutCall = “Put” Then
Price = Binomial(Spot, Strike, T, r, v, n, “Put”, “Euro”) - Op(1, 1)
End If
Case “Amer”
If PutCall = “Call” And UpType = “DI” Then
Price = (Spot / H) ^ (1 - 2 * r / v ^ 2) * Binomial(
H ^ 2 / Spot, Strike, T, r, v, n, “Call”, “Amer”)
End If
End Select
End If
BarrierDown = Price
End Function
Figure 8.4 illustrates this function on a European down-and-in call, using values similar to those in Figure 8.3. In cell F6 we type
FIGURE 8.4 Interpolated Price for a European Down-and-In Call
which produces a price of $5.7578. The exact price is $5.7636 (Haug, 1998). The price of an American down-and-in call with the same parameter values is $5.7667
Kwok and Dai (2004) show that the reflection principle (8.2) for pricing American down-and-in calls, and (8.3) for pricing up-and-in puts can be inaccurate, depending on whether the barrier lies above or below the strike price. Their method is more general because it allows for the barrier to lie anywhere relative to the strike price.
The free boundary S*(T) is the stock price at which it is optimal to exercise an American option with maturity T, so that S*(0) = max(rK/q, K) and
where r is the risk-free rate, q is the dividend yield, K is the strike price, and
where σ is the volatility.
When , Kwok and Dai (2004) show that the price of an American down-and-in call is given by
where T is the time to maturity, C(H2/S, T;K) is the price of a plain-vanilla American call with spot price H2/S, time to maturity T and strike price K, c(H2/S, T;K) is the European counterpart, and cdi(S, T;K, H) is the price of a European down-and-in call with spot price S, time to maturity T, strike K and barrier H. We use the CRR binomial tree to obtain the price of a down-and-out European call with the same parameters, and use the parity relationship (8.1) to obtain cdi(S, T;K, H) in (8.11).When H > S*(∞), Kwok and Dai (2004) show that the price is
where Φ() is the standard normal cumulative distribution function, and
In these expressions e2 is identical to e1 except that a minus sign replaces the plus sign in the numerator.
For American up-and-in puts, Kwok and Dai (2004) show that the analogous counterpart to (8.11) is
where P(H2/S, T;K) is the price of a plain-vanilla American put with spot price H2/S, and p(H2/S, T;K) is the price of a plain-vanilla European put.
The Excel file Chapter8AmerDICall contains the VBA function KDAmerCall() for implementing this method on American down-and-in calls. It uses the CRR binomial tree to obtain the value of a plain-vanilla call option and incorporates the optimal number of steps given by Boyle and Lau (1994). The first part of the function adjusts the barrier for barrier monitoring, chooses the optimal number of steps, and defines the CRR tree parameters. The second part of the function calculates the price of a European down-and-out call, which will be used to obtain the price of a European down-and-in call required in (8.11). The down-and-in call price is stored in Op(1,1).
Function KDAmerCall(Spot, Strike, Bar, T, r, q, v, old_n, M1, M2 As String)
For i = 1 To n + 1
AssetPrice = Spot * u ^ (n + 1 - i) * d ^ (i - 1)
If AssetPrice <= Bar Then
Op(i, n + 1) = 0
Else
Op(i, n + 1) = Application.Max(AssetPrice - Strike, 0)
End If
Next i
For j = n To 1 Step -1
For i = 1 To j
AssetPrice = Spot * u ^ (j - i) * d ^ (i - 1)
If AssetPrice <= Bar Then
Op(i, j) = 0
Else
Op(i, j) = exp_rT * (p * Op(i, j + 1) + (1 - p) * Op(i + 1, j + 1)
End If
Next i
Next j
The next part of the function defines the free boundary S*(∞). Since S*(∞) = ∞ when q = 0, or equivalently, when μ+ = 1, S*(∞) is set to a large number when q = 0 so that Equation (8.12) is used for the call price.
If q <> 0 Then
mu_plus = -(r - q - 0.5 * v ^ 2) / v ^ 2
+ Sqr((r - q - 0.5 * v ^ 2) ^ 2 + 2 * v ^ 2 * r) / v ^ 2
S_inf = mu_plus * Strike / (mu_plus - 1)
ElseIf q = 0 Then
S_inf = 999999999
End If
Finally, the barrier is compared to S*(∞), so that when Equation (8.11) is used, but when H > S*(∞) Equation is used. The option price and optimal number of steps are stored in array Output().
Select Case Bar
Case Is <= S_inf
DIEurocall =
fbinomial(Spot, Strike, r, q, v, T, n, “Euro”) - Op(1, 1)
output(1, 1) = (Spot / Bar) ^ (1 - 2 * (r - q) / v ^ 2)
* (fbinomial(Bar ^ 2 / Spot, Strike, r, q, v, T, n, “Amer”)
- fbinomial(Bar ^ 2 / Spot, Strike, r, q, v, T, n,
“Euro”)) + DIEurocall
Case Is >= S_inf
mu = Sqr((r - q - v ^ 2 / 2) ^ 2 + 2 * r * v ^ 2) / v ^ 2
alpha = 0.5 - (r - q) / v ^ 2
e1 = (Log(Bar / Spot) + mu * v ^ 2 * T) / v / Sqr(T)
e2 = (Log(Bar / Spot) - mu * v ^ 2 * T) / v / Sqr(T)
output(1, 1) = (Bar - Strike) * (Gauss(e1)
* (Spot / Bar) ^ (alpha - mu)
+ Gauss(e2) * (Spot / Bar) ^ (alpha + mu))
End Select
output(2, 1) = n
KDAmerCall = output
End Function
Figure 8.5 illustrates the KDAmerCall() function, on a down-and-in American call option with strike price K = 100, barrier H = 110 and time to maturity τ = 1 year, when the spot price is S = 120.5, the risk free rate, dividend yield and volatility are r = 0.10, q = 0.09, and σ = 0.30, respectively, and using n = 1, 000 steps. These are the same values as those used in Table 1 of Kwok and Dai (2004), except that they used n = 10, 000 steps to obtain the “exact” values in the last column of their table. In cell F5 we type
FIGURE 8.5 Down-and-In American Call
and copy down to cell F6, which produces a price of $12.5392 in cell F5 with an optimal number of steps n = 1, 082 in cell F6. The price is close to the value of $12.5409 obtained by Kwok and Dai (2004) in row 4 of their Table 1. In this example S*(∞) = 207.6 and H = 110, so Equation (8.11) is used for the price. Specifying S = 180.5 and H = 170 produces a price of $59.6083 with n = 1, 227 optimal time steps, reasonably close to the “exact” value of $59.3874 obtained in the last row, last column of Table 1 in Kwok and Dai (2004)
The Excel file Chapter8AmerUIPut contains the VBA function KDAmerPut() to implement the Kwok and Dai (2004) price of an American up-and-in put. The function is very similar to the KDAmerCall() function, except for the last part, which specifies that (8.14) use prices of puts instead of calls.
Select Case Bar
Case Is <= S_inf
DIEuroPut =
fbinomial(Spot, Strike, r, q, v, T, n, “Euro”) - Op(1, 1)
output(1, 1) = (Spot / Bar) ^ (1 - 2 * (r - q) / v ^ 2)*
(fbinomial(Bar ^ 2 / Spot, Strike, r, q, v, T, n, “Amer”)
- fbinomial(Bar ^ 2 / Spot, Strike, r, q, v, T, n,
“Euro”)) + DIEuroPut
Case Is >= S_inf
mu = Sqr((r - q - v ^ 2 / 2) ^ 2 + 2 * r * v ^ 2) / v ^ 2
alpha = 0.5 - (r - q) / v ^ 2
e1 = (Log(Bar / Spot) + mu * v ^ 2 * T) / v / Sqr(T)
e2 = (Log(Bar / Spot) - mu * v ^ 2 * T) / v / Sqr(T)
output(1, 1) = (Bar - Strike) * (Gauss(e1)
* (Spot / Bar) ^ (alpha - mu)
+ Gauss(e2) * (Spot / Bar) ^ (alpha + mu))
End Select
End If
output(2, 1) = n
KDAmerPut = output
End Function
Figure 8.6 illustrates the KDAmerPut() function on an American up-and-in put with strike price K = 100, barrier H = 110, and time to maturity T = 1 year, when the risk-free rate, dividend yield, and volatility are r = 0.05, q = 0.05, and σ = 0.30, and when n = 250 steps are used. In cell F5 we type
FIGURE 8.6 Up-and-In American Put
and copy down to cell F5, which produces a price of $4.5354, with an optimal number of steps n = 356
This method is due to Figlewski and Gao (1999) and was presented in Chapter 3 for pricing plain-vanilla options. It is very useful for pricing barrier options when the barrier is close to the spot price. It uses price increments h given
for building the coarse mesh in terms of log prices, where S is the spot price and H is the barrier, and time increments k given
where [x] denotes the floor function (the largest integer smaller than x), v is the volatility, and λ is an arbitrary free parameter. Figlewski and Gao (1999) recommend using λ = 3. The number of steps in the coarse mesh is given by rounding n = T/k to the nearest integer. The tree is constructed using a coarse mesh with 2n + 1 rows and n + 1 columns (the “A” points in Figure 6 of their paper), and a fine mesh with 3 rows and 4n + 1 columns (the “B” points). Finally, the probability for up moves is given by the function
the probability for a down move by the function
and the probability of a lateral move by
where α = r − v2/2 and r is the risk-free rate.
Finally, we note that since the time to maturity T and the volatility v are both fixed, and since h is fixed by (8.15), the only way to increase the number of time steps n in this model is to reduce k in (8.16) by increasing λ. Note also, however, that by virtue of (8.15) and (8.16), the closer the barrier to the spot price, the larger the number of time steps. In this chapter a single fine mesh is grafted on the coarse mesh, but as shown by Figlewski and Gao (1999) and as mentioned in Chapter 3, it is possible to graft a series of meshes, each one progressively finer, which increases the accuracy of the approximation to the option price even further.
The Excel file Chapter8BarrierAMM contains the VBA function BarrierAMM() for obtaining European and American single-barrier options with the AMM method. The function uses the VBA functions ProbUp() and ProbDown() for the up and down probabilities given in (8.17) and (8.18), respectively.
Function ProbUp(Alpha, v, h, k)
ProbUp = (v ^ 2 * k / h ^ 2 + Alpha ^ 2 * k ^ 2 / h ^ 2
+ Alpha * k / h) / 2
End Function
Function ProbDown(Alpha, v, h, k)
ProbDown = (v ^ 2 * k / h ^ 2 + Alpha ^ 2 * k ^ 2 / h ^ 2
- Alpha * k / h) / 2
End Function
The coarse mesh in terms of log prices (the “A” points) are constructed from a distance of h/2 about the log spot price, and stored in the array A(). The asset prices are constructed by exponentiating the “A” points. These are stored in the array S().
If BarType = “DO” Or BarType = “DI” Then
A(n + 1, 1) = Log(Spot) + h / 2
ElseIf BarType = “UO” Or BarType = “UI” Then
A(n + 1, 1) = Log(Spot) - h / 2
End If
For j = 1 To (n + 1)
For i = (n - j + 2) To (n + j)
A(i, j) = A(n + 1, 1) + (n - i + 1) * h
If A(i, j) = 0 Then
S(i, j) = 0
Else
S(i, j) = Exp(A(i, j))
End If
Next i
Next j
Finally, the option prices along the coarse mesh are obtained by the usual method of backward recursion, by using the probabilities given in (8.17) through (8.19) and exp(−rk) as the discount factor, verifying whether the current asset price lies above or below the barrier at each step, and checking for early exercise in the case of American options.
exp_rt = Exp(-r * k): pu = ProbUp(Alpha, v, h, k)
pd = ProbDown(Alpha, v, h, k): pm = 1 - pu - pd
For i = 1 To 2 * n + 1
Select Case PutCall
Case “Call”:
Op(i, n + 1) = Application.Max(S(i, n + 1) - Strike, 0)
Case “Put”:
Op(i, n + 1) = Application.Max(Strike - S(i, n + 1), 0)
End Select
If ((BarType = “DO” Or BarType = “DI”)
And A(i, n + 1) <= logH)
Or ((BarType = “UO” Or BarType = “UI”)
And A(i, n + 1) >= logH) Then
Op(i, n + 1) = 0
End If
Next i
For j = n To 1 Step -1
For i = (n - j + 2) To (n + j)
If ((BarType = “DO” Or BarType = “DI”)
And A(i, j) <= logH) _
Or ((BarType = “UO” Or BarType = “UI”)
And A(i, j) >= logH) Then
Op(i, j) = 0
Else
Select Case EuroAmer
Case “Amer”
If PutCall = “Call” Then
Op(i, j) = Application.Max(S(i, j) - Strike,
exp_rt * (pu * Op(i - 1, j + 1) + pm * Op(i, j + 1)
+ pd * Op(i + 1, j + 1)))
ElseIf PutCall = “Put” Then
Op(i, j) = Application.Max(Strike - S(i, j),
exp_rt * (pu * Op(i - 1, j + 1) + pm * Op(i, j + 1)
+ pd * Op(i + 1, j + 1)))
End If
Case “Euro”
Op(i, j) = exp_rt * (pu * Op(i - 1, j + 1)
+ pm * Op(i, j + 1) + pd * Op(i + 1, j + 1))
End Select
End If
Next i
Next j
The fine mesh (the “B” points) is constructed using time increments of k/4, so the discount factor becomes exp(−rk/4). The upper row retains the price increment h, so the probabilities (8.17) through (8.19) use v, h, and k/4. The array temp() contains temporary values which are transferred to the array B() of dimension 3 × (4n + 1)in subsequent steps.
exp_rt = Exp(-r * k / 4): pu = ProbUp(Alpha, v, h, k / 4)
pd = ProbDown(Alpha, v, h, k / 4): pm = 1 - pu - pd
For j = n + 1 To 2 Step -1
If EuroAmer = “Euro” Then
temp(j - 1) = exp_rt * (pu * Op(n, j) + pm*
Op(n + 1, j) + pd * Op(n + 2, j))
ElseIf EuroAmer = “Amer” And PutCall = “Call” Then
temp(j - 1) = Application.Max(S(n + 1, 1) - Strike,
exp_rt * (pu * Op(n, j) + pm * Op(n + 1, j)
+ pd * Op(n + 2, j)))
ElseIf EuroAmer = “Amer” And PutCall = “Put” Then
temp(j - 1) = Application.Max(Strike - S(n + 1, 1),
exp_rt * (pu * Op(n, j) + pm * Op(n + 1, j)
+ pd * Op(n + 2, j)))
End If
Next j
Dim B() As Double
ReDim B(3, 4 * n + 1) As Double
If BarType = “DO” Or BarType = “DI” Then
B(1, 4 * n + 1) = Op(n + 1, n + 1)
ElseIf BarType = “UO” Or BarType = “UI” Then
B(3, 4 * n + 1) = Op(n + 1, n + 1)
End If
For i = 3 To 4 * n + 1
If i Mod 4 = 0 Then
If BarType = “DO” Or BarType = “DI” Then
B(1, 1) = 0
B(1, i) = temp(i / 4)
B(1, i - 1) = B(1, i)
B(1, i - 2) = B(1, i)
B(1, i - 3) = B(1, i)
ElseIf BarType = “UO” Or BarType = “UI” Then
B(3, 1) = 0
B(3, i) = temp(i / 4)
B(3, i - 1) = B(3, i)
B(3, i - 2) = B(3, i)
B(3, i - 3) = B(3, i)
End If
End If
Next i
The middle row uses price increments of h/2, so the probabilities (8.17) through (8.19) use v, h/2, and k/4.
pu = ProbUp(Alpha, v, h / 2, k / 4)
pd = ProbDown(Alpha, v, h / 2, k / 4)
pm = 1 - pu - pd
For j = 4 * n To 1 Step -1
If BarType = “DO” Or BarType = “DI” Then
Asset = Exp(A(n + 1, 1) - h / 2)
ElseIf BarType = “UO” Or BarType = “UI” Then
Asset = Exp(A(n + 1, 1) + h / 2)
End If
Select Case EuroAmer
Case “Euro”
B(2, j) = exp_rt * (pu * B(1, j + 1) + pm * B(2, j + 1)
+ pd * B(3, j + 1))
Case “Amer”
Select Case PutCall
Case “Call”
B(2, j) = Application.Max(Asset - Strike,
exp_rt * (pu * B(1, j + 1) + pm*
B(2, j + 1) + pd * B(3, j + 1)))
Case “Put”
B(2, j) = Application.Max(Strike - Asset,
exp_rt * (pu * B(1, j + 1) + pm*
B(2, j + 1) + pd * B(3, j + 1)))
End Select
End Select
Next j
Finally, option prices are obtained in accordance with Table 8.1, using the trinomial tree of Chapter 3 for plain-vanilla options. The function outputs the option price and the number of steps, n, used to construct the meshes.
If BarType = “DO” Or BarType = “UO” Then
output(1, 1) = B(2, 1)
Else
Select Case EuroAmer
Case “Euro”
If PutCall = “Call” Then
output(1, 1) = Trinomial(Spot, Strike, T, r, v, n,
“Call”, “Euro”) - B(2, 1)
ElseIf PutCall = “Put” Then
output(1, 1) = Trinomial(Spot, Strike, T, r, v, n,
“Put”, “Euro”) - B(2, 1)
End If
Case “Amer”
If PutCall = “Call” And BarType = “DI” Then
output(1, 1) = (Spot / Bar) ^ (1 - 2 * r / v ^ 2)*
Trinomial(Bar ^ 2 / Spot, Strike, T, r,
v, n, “Call”, “Amer”)
ElseIf PutCall = “Put” And BarType = “UI” Then
output(1, 1) = (Spot / Bar) ^ (1 - 2 * r / v ^ 2)*
Trinomial(Bar ^ 2 / Spot, Strike, T, r,
v, n, “Put”, “Amer”)
ElseIf (PutCall = “Put” And BarType = “DI”) Then
MsgBox “You Cannot Price an American Down-and-In Put
Using This Algorithm”
ElseIf (PutCall = “Call” And BarType = “UI”) Then
MsgBox “You Cannot Price an American Up-and-In Call
Using This Algorithm”
End If
End Select
End If
output(2, 1) = n
BarrierAMM = output
End Function
Figure 8.7 presents an example of the BarrierAMM() function, on an up-and-in European single-barrier put option monitored continuously, with spot price S = 100, strike price K = 100, barrier H = 100.5, and time to maturity T = 0.5 years, when the interest rate is r = 0.05, the yearly volatility is v = 0.30 (30 percent), and using λ = 3. In cell F8 we type
FIGURE 8.7 Adaptive Mesh Method for Single Barrier Options
which produces the same value of 100.5 for the barrier, since “C” appears in cell C17, indicating continuous monitoring. In cell F6 we type
and copy the function to cell F7. This produces an option price of $6.7655 in cell F6, and indicates that n = 1, 356 was used to construct the adaptive mesh in cell F7. The analytic price of this option is $6.7663 (see Haug, 1998). The price of the American option with identical parameters is $6.9770
In the last part of this section, prices of down-and-out American single-barrier call options are obtained using different methods and are compared, using the same inputs as in Figure 8.5. This comparison is in the Excel file Chapter8BarrierComp, and appears in Figure 8.8
FIGURE 8.8 Comparison of Prices for Barrier Options
With n = 300 steps, the Boyle and Lau (1994) method selects n = 389 as the optimal number of steps, and produces a price of 15.2295, comparable to that produced by the interpolation method of Derman et al. (1995) and the adaptive mesh method of Figlewski and Gao (1999). The method of Kwok and Dai (2004) produces a price that is slightly lower.
Digital options are options with discontinuous payoffs. In this section two types of digital options are examined. Cash-or-nothing calls pay a fixed amount, Q, if the asset price is above the strike price, and pay nothing otherwise. Cash-or-nothing puts pay Q if the asset price is below the strike price, and nothing otherwise. Hence the payoff from a cash-or-nothing option is either zero or Q. Asset-or-nothing calls and puts are identical, except that the payoff is the terminal asset price rather than Q.
Pricing European cash-or-nothing and asset-or-nothing options under risk neutrality and assuming stock price dynamics identical to those giving rise to the Black-Scholes formula, is straightforward and is explained in Hull (2006) and Haug (1998). The prices of these options under these conditions are presented Table 8.2. In this table, ST is the asset price at maturity, Φ() is the standard normal cumulative distribution function, S is the spot price, K the strike price, T the time to maturity, r and q are the risk-free rate and the dividend yield or foreign risk-free rate, respectively, σ is the volatility, and d1 and d2 are the usual quantities
TABLE 8.2 European Digital Options
For American digital calls, the strike price must be above the spot price, and for American digital puts, the strike price must be below the spot price. If this condition is not met and the option price is less than the payoff Q, then an arbitrage opportunity is possible by buying the option and exercising it immediately.
The Excel file Chapter8CashorNothing uses the Leisen-Reimer binomial tree to produce the price of European or American cash-or-nothing options, through the VBA function LRCash(). The first part of the function defines the parameters and constructs the tree, stored in array S(). It is identical to the LRBinomial() function of Chapter 3 and will not be presented here. The second part compares the terminal prices to the strike price, and sets the option price to zero or to the payoff, depending on which condition is met. American options are priced by using the usual method of backward recursion. To allow for the dividend yield q, in the Leisen-Reimer tree we define d1 and d2 as in (8.20), and we define rn = exp[(r − q)T/n] rather than rn = exp[rT/n].
Function LRCash(Spot, K, PayOff, T, r, q, v, n, PutCall As String, EuroAmer As String, Method)
For i = 1 To n + 1
Select Case PutCall
Case “Call”:
If S(i, n + 1) >= K Then
Op(i, n + 1) = PayOff
Else
Op(i, n + 1) = 0
End If
Case “Put”:
If S(i, n + 1) >= K Then
Op(i, n + 1) = 0
Else
Op(i, n + 1) = PayOff
End If
End Select
Next i
The next part of the function discounts the expected terminal option prices to time zero (for European options) and compares the option prices to the payoff (for American options), in the usual manner.
For j = n To 1 Step -1
For i = 1 To j
Select Case EuroAmer
Case “Euro”:
Op(i, j) = Exp(-r * dt) * (p * Op(i, j + 1)
+ (1 - p) * Op(i + 1, j + 1))
Case “Amer”:
If S(i, j) >= K Then
Select Case PutCall
Case “Call”:
Op(i, j) = Application.Max(PayOff, Exp(-r * dt)*
* (p * Op(i, j + 1) + (1 - p) * Op(i + 1, j + 1)))
Case “Put”:
Op(i, j) = Application.Max(0, Exp(-r * dt)*
(p * Op(i, j + 1) + (1 - p) * Op(i + 1, j + 1)))
End Select
Else
Select Case PutCall
Case “Call”:
Op(i, j) = Application.Max(0, Exp(-r * dt)*
(p * Op(i, j + 1) + (1 - p) * Op(i + 1, j + 1)))
Case “Put”:
Op(i, j) = Application.Max(PayOff, Exp(-r * dt)
* (p * Op(i, j + 1) + (1 - p) * Op(i + 1, j + 1)))
End Select
End If
End Select
Next i
Next j
Finally, the option price is contained in Op(1,1), and for European options the analytical price from Table 8.2 is obtained also.
If EuroAmer = “Euro” Then
Select Case PutCall
Case “Call”: Analytic = PayOff * Exp(-r * T)
* Application.NormSDist(d2)
Case “Put”: Analytic = PayOff * Exp(-r * T)
* Application.NormSDist(-d2)
End Select
End If
output(1, 1) = Op(1, 1)
If EuroAmer = “Euro” Then output(2, 1) = Analytic
If EuroAmer = “Amer” Then output(2, 1) = “Euro Only”
LRCash = output
End Function
Figure 8.9 illustrates a cash-or-nothing option with payoff of $10, maturity 6 months and strike price K = 40, when the spot price is S = 30, the yearly risk-free rate and dividend yield are r = 0.05 and q = 0.01, respectively, the yearly volatility is σ = 0.30, and with n = 250 steps
FIGURE 8.9 European Cash-or-Nothing Call
To obtain the price of the cash-or-nothing option with these values, in cell C19 we type
which produces a price of $0.8355, identical within six decimal places to the analytical price in cell C20. The price of an American option with the same parameter values is $1.5998.
As mentioned above, asset-or-nothing options are similar to cash-or-nothing options, except that the payoff is the terminal asset price rather than Q. To price these options, we use the same Leisen-Reimer binomial tree as we used for the cash-or-nothing options, except that whenever the payoff Q is encountered in the function, it is replaced by the current asset price S(i, j). The Excel file Chapter8AssetorNothing produces the prices of European and American asset-or-nothing options, through the VBA function LRAsset(). Figure 8.10 illustrates the function on a European asset-or-nothing call with the same parameters as the cash-or-nothing call presented in Figure 8.9 above
FIGURE 8.10 European Asset-or-Nothing Call
To obtain the price of the option with these parameter values, in cell C18 we type
and copy down to cell C19, which produces a price of 3.6979. As can be seen from the figure, the option price in cell C18 obtained from the Leisen-Reimer tree is very close to the analytical price in cell C19. The price of an American asset-or-nothing call is $6.4400 when the same parameter values are used.
Asian options are options for which the payoff depends on the average price of the asset during the life of the option. The average asset price can be the arithmetic average or the geometric average
. In this section we use the method of Hull and White (1993) for path-dependent derivatives to obtain the price of Asian options where the payoff depends on the arithmetic average S. The payoffs we consider are those of the form max(S − K, 0) for an Asian call, and max(K − S, 0) for an Asian put.
Hull and White (1993) describe a general procedure for valuing path-dependent derivatives, namely derivatives whose payoffs depend not only on the current or final asset price, but also on the price path of the asset during the life of the option. Asian options and lookback options are examples of such derivatives. To price these derivatives using a tree-based method, at each node all possible price paths must be must be evaluated along with the path function, F(t), which can be cumbersome and computationally extensive. The procedure proposed by Hull and White (1993) requires that only representative values of F(t) need be evaluated at each node, such as the minimum and maximum values of F(t), Fmin(t) and Fmax(t). The price of the derivative is evaluated at the representative values, and the prices for other values of F(t) are obtained by interpolation. Increasing the time steps and the number of interpolation points increases the accuracy of the approximation. For this method to work, the function payoff must depend on a single path function, and it must be possible to obtain the value of F(t + dt) using only F(t) and the asset price at time t. For further explanation of this procedure, and a thorough example that includes a detailed diagram, see Hull (2006).
The Excel file Chapter8Asian contains the VBA function Asian() for implementing this procedure. This function relies heavily on three-dimensional arrays in VBA. The first part of the function defines the CRR binomial tree parameters and constructs the CRR tree, the values of which are stored in the array S(). The second part of the function defines Fmin(t) and Fmax(t), which are the minimum and maximum average stock price values, and are stored in the arrays F(i, j, 1) and F(i, j, NumAvg), respectively. NumAvg is a parameter specified by the user for the number of interpolated points between Fmin(t) and Fmax(t). Interpolated values of the path function are stored in the arrays F(i, j, k), where 1 < k < NumAvg. The value of the path function at time zero, F(0), is set to the spot price.
Function Asian(Spot, Strike, T, r, v, n, NumAvg, PutCall As String, EuroAmer As String)
Dim F() As Double
ReDim F(n + 1, n + 1, NumAvg) As Double
For j = 2 To n + 1
For i = 1 To j
M1 = 0: M2 = 0
M3 = 0: M4 = 0
For k = 1 To j - i + 1
M1 = M1 + S(i, j - k + 1)
Next k
For k = 1 To i - 1
M2 = M2 + S(i - k, i - k)
Next k
F(i, j, 1) = (M1 + M2) / j
For k = 1 To i
M3 = M3 + S(i - k + 1, j - k + 1)
Next k
For k = 1 To j - i
M4 = M4 + S(1, j - i - k + 1)
Next k
F(i, j, NumAvg) = (M3 + M4) / j
For k = 2 To NumAvg - 1
F(i, j, k) = F(i, j, 1) + (k - 1)*
(F(i, j, NumAvg) - F(i, j, 1)) / (NumAvg - 1)
Next k
Next i
Next j
For k = 1 To NumAvg
F(1, 1, k) = S(1, 1)
Next k
The next part of the function works backward through each path function subarray and creates new values of the path function when the asset price moves up and down, and stores these in the arrays NewFU() and NewFD(), respectively. The values in NewFU(), NewFD(), and F() are then rounded off to the nearest thousandths.
For k = 1 To NumAvg
For j = n To 1 Step -1
For i = 1 To j
NewFU(i, j, k) = (j * F(i, j, k) + S(i, j + 1)) / (j + 1)
NewFU(i, j, k) = Application.Round(NewFU(i, j, k), 4)
NewFD(i, j, k) = (j * F(i, j, k) + S(i + 1, j + 1)) / (j + 1)
NewFD(i, j, k) = Application.Round(NewFD(i, j, k), 4)
Next i
Next j
Next k
For j = 1 To n + 1
For i = 1 To j
For k = 1 To NumAvg
F(i, j, k) = Application.Round(F(i, j, k), 4)
Next k
Next i
Next j
Next, the terminal prices of the options are obtained and stored in the array Op().
Dim Op() As Variant
ReDim Op(n + 1, n + 1, NumAvg) As Variant
For k = 1 To NumAvg
For i = 1 To n + 1
Select Case PutCall
Case “Call”: Op(i, n + 1, k) = Application.Max(0,
F(i, n + 1, k) - Strike)
Case “Put”: Op(i, n + 1, k) = Application.Max(0,
Strike - F(i, n + 1, k))
End Select
Next i
Next k
Finally, the option prices are interpolated using the arrays F(), NewFU(), and NewFD(). Following interpolation, prices for European and American options are obtained by the usual method of backward recursion, and the final price is stored in Op(1,1).
For j = n To 1 Step -1
For i = 1 To j
For k = 1 To NumAvg
For m = 1 To NumAvg - 1
If (F(i, j + 1, m) <= NewFU(i, j, k))
And (NewFU(i, j, k) <= F(i, j + 1, m + 1)) Then
X0 = F(i, j + 1, m)
Y0 = Op(i, j + 1, m)
X1 = F(i, j + 1, m + 1)
Y1 = Op(i, j + 1, m + 1)
X = NewFU(i, j, k)
UU = Op(i, j + 1, m)
If X1 <> X0 Then
UU = ((X - X0) * Y1 + (X1 - X) * Y0) / (X1 - X0)
End If
End If
Next m
For m = 1 To NumAvg - 1
If (F(i + 1, j + 1, m) <= NewFD(i, j, k))
And (NewFD(i, j, k) <= F(i + 1, j + 1, m + 1)) Then
X0 = F(i + 1, j + 1, m)
Y0 = Op(i + 1, j + 1, m)
X1 = F(i + 1, j + 1, m + 1)
Y1 = Op(i + 1, j + 1, m + 1)
X = NewFD(i, j, k)
DD = Op(i + 1, j + 1, m)
If X1 <> X0 Then
DD = ((X - X0) * Y1 + (X1 - X) * Y0) / (X1 - X0)
End If
End If
Next m
If k = 1 Then UU = Op(i, j + 1, 1)
If k = NumAvg Then DD = Op(i + 1, j + 1, NumAvg)
Select Case EuroAmer
Case “Euro”:
Op(i, j, k) = exp_rT * (p * UU + (1 - p) * DD)
Case “Amer”:
If PutCall = “Call” Then
Op(i, j, k) = Application.Max(F(i, j, k) - Strike,
exp_rT * (p * UU + (1 - p) * DD))
End If
If PutCall = “Put” Then
Op(i, j, k) = Application.Max(Strike - F(i, j, k),
exp_rT * (p * UU + (1 - p) * DD))
End If
End Select
Next k
Next i
Next j
Asian = Op(1, 1, 1)
End Function
Figure 8.11 illustrates the VBA function Asian(), on an Asian call option of the American type with time to maturity T = 1 year and strike price K = 50, on a non-dividend-paying stock with spot price S = 50, when the risk free rate is r = 0.10, the volatility is σ = 0.40, with n = 20 and NumAvg = 4 interpolations between Fmin(t) and Fmax(t). This is the same example that is described in Chapters 22 and 24 of Hull (2006). In cell C15 we type
FIGURE 8.11 Asian Call Option of the American Type
which produces a price of $7.77. Increasing the steps to n = 60 and the number of averages to NumAvg = 100 produces a price of $6.17. The price of a European option with these latter values is $5.58
Lookback options are another type of path-dependent option. The payoff of these options depends on the maximum stock price, Smax or minimum stock price, Smin of the asset during the life of the option. The payoffs from a floating strike lookback call and put are given by max(ST − Smin, 0) and max(Smax − ST, 0), respectively, where ST is the terminal asset price. Cheuk and Vorst (1997) describe a simple method to price floating-strike lookback options. At any time, the call price can be expressed as the product of the asset price and a function V, and the put price as the product of the asset price and a function X. Binomial trees are constructed for V (their Figure 2) and for X (their Figure 3), and the option price in terms of X and V is obtained by backward recursion through the trees.
For floating-strike lookback calls, the tree has elements V(i, j) = 1 − dj−i and for puts the tree has elements X(i, j) = uj−i − 1. For a tree with n steps the terminal option prices are set as V(i, n + 1) and X(i, n + 1). When i ≠ j the price at the (i, j)th node of an American call fij is given by
If fij denotes the price of a European call, then the maximum comparison with V(i, j) is not made, and the price is
If fij denotes the price of an American put, then
When i = j these expressions become
and
for American calls and puts, respectively. The European counterparts are obtained analogously to (8.22), by ignoring the maximum comparison with V(i, j) and X(i, j). For European and American calls and puts the option price is obtained by multiplying f1, 1 by the spot price. A description of this method is also available as Technical Note 13 on John Hull’s Web site. This procedure is very similar to the one proposed by Babbs (2000).
The Excel file Chapter8LookbackFloat contains the VBA function LBFloat() for implementing this method. The first part of the function defines the CRR tree parameters, constructs the trees for Vand X and creates the terminal option prices.
Function LBFloat(Spot, T, r, q, sigma, n, CallPut As String, EuroAmer As String)
dt = T / n: u = Exp(sigma * Sqr(dt))
d = 1 / u: p = (Exp((r - q) * dt) - d) / (u - d)
exp_rT = Exp(-r * dt)
Dim X(), V(), Op() As Double
ReDim V(n + 1, n + 1), X(n + 1, n + 1), Op(n + 1, n + 1) As Double
For i = 1 To n + 1
For j = i To n + 1
X(i, j) = u ^ (j - i) - 1
V(i, j) = 1 - d ^ (j - i)
If j = n + 1 Then
Select Case CallPut
Case “Call”: Op(i, j) = V(i, j)
Case “Put”: Op(i, j) = X(i, j)
End Select
End If
Next j
Next i
The next part computes the option prices through backward recursion, using equations (8.21) through (8.25).
For j = n To 1 Step -1
For i = 1 To j
If i <> j Then
Select Case EuroAmer
Case “Euro”:
If CallPut = “Put” Then
Op(i, j) = exp_rT * ((1 - p) * Op(i, j + 1) * d
+ p * Op(i + 2, j + 1) * u)
ElseIf CallPut = “Call” Then
Op(i, j) = exp_rT * (p * Op(i, j + 1) * u + (1 - p)
* Op(i + 2, j + 1) * d)
End If
Case “Amer”:
If CallPut = “Put” Then
Op(i, j) = Application.Max(X(i, j), exp_rT * ((1 - p)
* Op(i, j + 1) * d + p * Op(i + 2, j + 1) * u))
ElseIf CallPut = “Call” Then
Op(i, j) = Application.Max(V(i, j), exp_rT
* (p * Op(i, j + 1) * u + (1 - p)
* Op(i + 2, j + 1) * d))
End If
End Select
Else
Select Case EuroAmer
Case “Euro”:
If CallPut = “Put” Then
Op(i, j) = exp_rT * ((1 - p) * Op(i, j + 1) * d
+ p * Op(i + 1, j + 1) * u)
ElseIf CallPut = “Call” Then
Op(i, j) = exp_rT * (p * Op(i, j + 1) * u
+ (1 - p) * Op(i + 1, j + 1) * d)
End If
Case “Amer”:
If CallPut = “Put” Then
Op(i, j) = Application.Max(X(i, j), exp_rT * ((1 - p)
* Op(i, j + 1) * d + p * Op(i + 1, j + 1) * u))
ElseIf CallPut = “Call” Then
Op(i, j) = Application.Max(V(i, j), exp_rT
* (p * Op(i, j + 1) * u + (1 - p)
* Op(i + 1, j + 1) * d))
End If
End Select
End If
Next i
Next j
LBFloat = Spot * Op(1, 1)
End Function
Figure 8.12 illustrates this function on a floating strike lookback call with maturity T = 0.5 years, when the spot price is n = 1,000, the risk free rate is r = 0.04 and the dividend yield is q = 0.07, using n = 50 steps. In cell C14 we type
FIGURE 8.12 Floating-Strike Lookback Call
which produces a price of $8.97. With n = 100, n = 500, and n = 1,000 the prices are $9.20, $9.52, and $9.60, respectively. These are the same prices that appear in Table 1 of Cheuk and Vorst (1997)
Barrier options are very popular among investors, but using tree-based methods to price these types of exotic options can be problematic because the barrier almost never lies on any of the price nodes. Boyle and Lau (1994) provide a very simple solution to this problem, by selecting the number of steps in a binomial tree so that asset prices lie as close as possible to the barrier. In the method due to Tian (1999) the first stage of the tree is tilted to ensure that the asset price nodes lie on the barrier in the second stage. The interpolation method of Derman et al. (1995) and the adaptive mesh method of Figlewski and Gao (1999) are more complicated but also produce good results. Obtaining the price of down-and-out and up-and-out options with tree-based methods is relatively simple. Down-and-in and up-and-in European barrier options can then be priced using the parity relationship (8.1). American barrier options can be priced using the reflection principle and the method of Kwok and Dai (2004). Adjustments to the barrier for discrete monitoring can be done using the method of Broadie, Glasserman, and Kou (1997, 1999).
In this chapter, it is shown also that digital cash-or-nothing and asset-or-nothing options can be priced very effectively using Leisen and Reimer (1996) binomial trees. Asian options can be priced using the method of Hull and White (1993), but unfortunately this method requires many interpolations and can be quite computer intensive. Finally, prices of floating-strike lookback options are obtained using a procedure described by Cheuk and Vorst (1997).
This section provides exercises that deal with exotic options. Solutions are contained in the Excel file Chapter8Exercises.
8.1 Capped options are similar to plain-vanilla options, except that the payoff is subject to a limit. Boyle and Lau (1994) show that binomial trees can be used to price capped options effectively when the optimal number of steps is chosen by (8.8), where now H represents the payoff limit. For H > K, the payoff of a capped call is H − K when ST > H, it is ST − K when K < ST < H, and it is zero when ST < K, where K is the strike price and ST is the terminal price of the asset. Write a VBA program for the price of European and American capped calls, using the optimal number of steps suggested by Boyle and Lau (1994).
8.2 A fixed-strike lookback call has payoff given by max(0, Smax − K), and a fixed-strike lookback put a payoff max(0, K − Smin). By redefining X(i, j) = uj−i and V(i, j) = dj−i, using X for calls and V for puts, modify the LRFloat() function to price the European versions of these options.
8.3 A shout floor is a shout option for which the holder of the option can “shout” to the issuer to impose a lower limit on the return. The limit is taken to be the asset price at the time the time of shouting. Dai, Kwok, and Wu (2004) present a model in which the price of a shout floor is
when and
when r > q, where T* is the unique positive root of the derivative d[e−qTP(T)]/dT and where r and q are the risk free rate and the dividend yield, respectively. The price function P(T) is given by
where Φ(x) is the cumulative distribution function of the standard normal variable, where
and . Write a VBA function to implement this model.
8.1 The VBA function CappedCall() to implement the price of a capped call resembles the code for a barrier option, except with additional conditions on the payoff. The first part of the function is identical to the BarrierBin() function described in this chapter. The second part specifies the terminal option prices.
Function CallCap(Spot, K, H, T, r, v, old_n, EuroAmer As String)
For i = 1 To n + 1
AssetPrice = Spot * u ^ (n + 1 - i) * d ^ (i - 1)
If AssetPrice >= H Then
Op(i, n + 1) = H - K
ElseIf (K <= AssetPrice And AssetPrice < H) Then
Op(i, n + 1) = AssetPrice - K
Else
Op(i, n + 1) = 0
End If
Next i
The remaining part of the function calculates the price of European capped calls by backward recursion through the tree, and with the additional comparisons on the payoff conditions for American calls. Figure 8.13 illustrates the function on an American capped call with time to maturity 4 years, spot price S = 25, strike K = 25, limit H = 40 and risk free rate r = log(1.08) when the volatility is σ = 0.40. These are the same values as those used in Exhibit 4 of Boyle and Lau (1994). The price of the capped call option is $7.6150, using n = 72 steps. When S = 30 and with n = 69 time steps, the price increases to $10.1125. These are the same values that appear in Boyle and Lau (1994)
FIGURE 8.13 Solution to Exercise
8.2 The VBA function LBFixed() is identical to LBFloat() function described in this chapter, except that the tree for calls is built for X and the tree for puts is built for V.
Function LBFixed(S, K, T, r, q, sigma, n, CallPut As String)
For i = 1 To n + 1
For j = i To n + 1
X(i, j) = u ^ (j - i)
V(i, j) = d ^ (j - i)
If j = n + 1 Then
Select Case CallPut
Case “Put”: Op(i, j) = V(i, j)
Case “Call”: Op(i, j) = X(i, j)
End Select
End If
Next j
Next i
The last part of the function creates the payoff, which uses the strike price discounted to time zero.
Select Case CallPut
Case “Call”
LBFixed = Application.Max(0, S * Op(1, 1) - K * Exp(-where * T))
Case “Put”
LBFixed = Application.Max(0, K * Exp(-r * T) - S * Op(1, 1))
End Select
End Function
Figure 8.14 illustrates this function on a European fixed-strike lookback call with strike K = 100 and n = 100 steps. The function produces a price of $10.0273 in cell C14. With n = 500 steps, the price is $10.4268. These prices are identical to those in Exhibit 5 of Choi and Jameson (2003)
FIGURE 8.14 Solution to Exercise
8.3 When it is straightforward to obtain the price function P(T), which we store as BigP in the ShoutFloor() VBA function.
Function BigP(r, q, T, v)
d1 = (r - q + 0.5 * v ^ 2) * Sqr(T) / v
d2 = d1 - v * Sqr(T)
BigP = Exp(-r * T) * Gauss(-d2) - Exp(-q * T) * Gauss(-d1)
End Function
Function ShoutFloor(S, r, q, T, v, a, b) As Variant
Dim Tstar As Variant
If r <= q Then
Price = S * BigP(r, q, T, v)
Tstar = “N / A”
Else
Tstar = BisMet(a, b, r, q, v)
If (0 < T) And (T <= Tstar) Then
Price = S * BigP(r, q, T, v)
ElseIf T >= Tstar Then
Price = Exp(-q * (T - Tstar)) * S * BigP(r, q, Tstar, v)
End If
End If
Dim output() As Variant
ReDim output(2, 1) As Variant
output(1, 1) = Price
output(2, 1) = Tstar
ShoutFloor = output
End Function
To find the root T* we need a root-finding method, such as the bisection method. We modify this method to accept the parameters of the pricing function. Note that the derivative of the pricing function is
where d′1 = d1/(2T) and .
Function BisMet(a, b, r, q, v)
EPS = 0.000001
MaxIter = 500
cnt = 0
If (Theta(r, q, a, v) * Theta(r, q, b, v) > 0) Then
MsgBox “Choose Other Bisection Parameters”
Else
Do While ((Abs(Theta(r, q, a, v) - Theta(r, q, b, v)) >
EPS) And (cnt < MaxIter))
midPt = (b + a) / 2
If Theta(r, q, midPt, v) < 0 Then
b = midPt
Else
a = midPt
End If
cnt = cnt + 1
Loop
BisMet = (b + a) / 2
End If
End Function
Function Theta(r, q, T, v)
d1 = (r - q + 0.5 * v ^ 2) * Sqr(T) / v
d2 = d1 - v * Sqr(T)
dp1 = d1 / 2 / T
dp2 = dp1 - v / 2 / Sqr(T)
BigP2 = Exp(-r * T) * Gauss(-d2) - Exp(-q * T) * Gauss(-d1)
dBigP = Exp(-r * T) * (-r * Gauss(-d2) - f(-d2) * dp2)
+ Exp(-q * T) * (q * Gauss(-d1) + f(-d1) * dp1)
Theta = Exp(q * T) * (q * BigP2 + dBigP)
End Function
When the ShoutFloor() function calculates the price as the product of the pricing function (8.28) and the spot price. When r > q then function finds the root of the derivative (8.30) using the bisection method via the VBA function BisMet().
Function ShoutFloor(S, r, q, T, v, a, b) As Variant
Dim Tstar As Variant
If r <= q Then
Price = S * BigP(r, q, T, v)
Tstar = “N / A“
Else
Tstar = BisMet(a, b, r, q, v)
If (0 < T) And (T <= Tstar) Then
Price = S * BigP(r, q, T, v)
ElseIf T >= Tstar Then
Price = Exp(-q * (T - Tstar)) * S * BigP(r, q, Tstar, v)
End If
End If
Dim output() As Variant
ReDim output(2, 1) As Variant
output(1, 1) = Price
output(2, 1) = Tstar
ShoutFloor = output
End Function
Figure 8.15 illustrates these functions when S = 100, K = 100, T = 5 years, σ = 0.20, r = 0.06, and q = 0.12. The price appears in cell C11 as $23.4209. When q = 0.03 the bisection method uses the starting values in cells C16 and C17 to find the root T* = 8.91, which appears in cell C12. This produces a price of $8.9487. Note that when T < T* the price of the shout floor is equal to the price of an at-the-money put option. The Black-Scholes put price appears in cell C13. These numbers are all identical to those in Table 8.1 of Dai, Kwok, and Wu (2004)
FIGURE 8.15 Solution to Exercise