SigmaField
Mathematical Foundations for Quant Finance
0 of 256 lessons
      1. 6.2.1 Constant coefficients and the characteristic equationConcept · 35 min
      2. 6.2.2 General solutions and boundary conditionsConcept · 35 min
      3. 6.2.3 Practice set: second-order equationsPractice set · 20 min
      4. 6.2.4 Case study: the perpetual American putCase study · 35 min

Level 6, Differential equations 6.2 Second-order linear ODEs Lesson 4 of 4

Case studyLesson 6.2.4 in Level 6, Differential equations. About 35 minutes.

Case study: the perpetual American put

A put that never expires

A put gives the right to sell a stock at the strike KK. Exercised when the stock price is SS, it pays K−SK - S; it is worth exercising only when S<KS < K. An American put may be exercised at any time (case study 5.11.4), and a perpetual one has no expiry date at all.

The inputs are those of case study 2.4.6: strike K=100K = 100, interest rate r=0.03r = 0.03 (continuous) and volatility σ=0.2\sigma = 0.2, both yearly decimals. The stock starts at S=100S = 100 and pays no dividends.

With no expiry, nothing changes as time passes except the stock price. A holder facing the price 80 next year faces the same problem as a holder facing 80 today. So the value is a function of the price alone, V(S)V(S).

The equation

For an option whose value V(S,t)V(S, t) depends on the price and the time, the Black–Scholes equation holds wherever the holder keeps the option:

∂V∂t+12σ2S2∂2V∂S2+rS∂V∂S−rV=0\begin{gathered} \frac{\partial V}{\partial t} + \frac{1}{2}\sigma^2S^2\frac{\partial^2 V}{\partial S^2} \\ + rS\frac{\partial V}{\partial S} - rV = 0 \end{gathered}

This case study only states it. Case study 6.3.4 states the full equation and checks it on the Black–Scholes formula; the Stochastic Calculus course derives it.

Here VV does not depend on tt, so the first term is 0 (case study 6.3.4 notes this too). The partial derivatives (lesson 4.1.2) become ordinary ones:

12σ2S2 V′′+rS V′−rV=0\tfrac{1}{2}\sigma^2S^2\,V'' + rS\,V' - rV = 0

That is the equidimensional equation of lesson 6.2.2, with x=Sx = S, a=12σ2a = \frac{1}{2}\sigma^2, b=rb = r and c=−rc = -r.

Its terms all have the same units. σ2\sigma^2 and rr are per year and VV is in dollars; V′V' is in dollars per dollar of SS, and V′′V'' in dollars per dollar squared. So each term is in dollars per year.

Trying V=SpV = S^p

Lesson 6.2.2's trial V=SpV = S^p turns the equation into one for pp:

12σ2p(p−1)+rp−r=0\tfrac{1}{2}\sigma^2p(p - 1) + rp - r = 0

Multiply by 2σ2\frac{2}{\sigma^2} and write β=2rσ2\beta = \frac{2r}{\sigma^2}, a pure number with no units (beta). The equation becomes

p(p−1)+βp−β=0(p−1)(p+β)=0\begin{gathered} p(p - 1) + \beta p - \beta = 0 \\[4pt] (p - 1)(p + \beta) = 0 \end{gathered}

So p=1p = 1 or p=−βp = -\beta, and the general solution is V=AS+BS−βV = AS + BS^{-\beta}. For the inputs above, β=2×0.030.04=1.5\beta = \frac{2 \times 0.03}{0.04} = 1.5.

The solution V=SV = S is the stock itself: a share solves the equation. The other, S−1.5S^{-1.5}, falls as the price rises, as a put's value should.

Try it

np.roots (lesson 1.2.2) solves 12σ2p2+(r−12σ2)p−r=0\frac{1}{2}\sigma^2p^2 + (r - \frac{1}{2}\sigma^2)p - r = 0, the equation for pp multiplied out.

residual puts SpS^p into the left side of the equation, at S=50S = 50, 100 and 150. The powers 1 and −1.5-1.5 leave 0; the power 2 does not.

⌘/Ctrl + Enter runs the cell

The boundary conditions

Two conditions fix AA and BB, one at each end of the range where the holder keeps the put.

Far away. As S→∞S \to \infty, the stock is ever less likely to fall below the strike, and the put is worth ever less: V→0V \to 0. The term ASAS grows, so A=0A = 0, as in lesson 6.2.2's condition at infinity. That leaves V=BS−βV = BS^{-\beta}.

At the exercise price. The holder exercises when the price falls to some level S∗S^*, the exercise boundary, and receives K−S∗K - S^* there. So V(S∗)=K−S∗V(S^*) = K - S^*, which gives B=(K−S∗)(S∗)βB = (K - S^*)(S^*)^{\beta} and

V(S)=(K−S∗)(SS∗)−βfor S≥S∗\begin{gathered} V(S) = (K - S^*)\left(\frac{S}{S^*}\right)^{-\beta} \\ \text{for } S \ge S^* \end{gathered}

Below S∗S^* the put is exercised at once, so V(S)=K−SV(S) = K - S there.

Which boundary?

The two conditions give a value for every choice of S∗S^*, so the boundary is part of the answer: this is a free-boundary problem. The holder chooses the S∗S^* that makes the put worth most. With the stock at 100:

exercise at S∗S^*40505560657080
value at S=100S = 10015.178917.677718.355118.590318.341617.569914.3108

Exercising early, at 80, gives up too much of the chance of a deeper fall. Waiting for 40 risks never getting there. The best is 60.

Calculus finds it exactly (lesson 2.4.1). Only (K−S∗)(S∗)β(K - S^*)(S^*)^{\beta} depends on S∗S^*. Its derivative is (S∗)β−1[β(K−S∗)−S∗](S^*)^{\beta - 1}\big[\beta(K - S^*) - S^*\big], which is 0 when

S∗=βK1+β=1.5×1002.5=60\begin{gathered} S^* = \frac{\beta K}{1 + \beta} \\ = \frac{1.5 \times 100}{2.5} = 60 \end{gathered}

The best boundary does not depend on today's price SS. So the rule is the same wherever the stock is: wait until it first falls to 60, then exercise.

Smooth pasting

At S∗=60S^* = 60 the slope of the value is V′(S∗)=−β K−S∗S∗=−1.5×4060=−1V'(S^*) = -\beta\,\frac{K - S^*}{S^*} = -1.5 \times \frac{40}{60} = -1. That is the slope of the payoff K−SK - S. The value curve meets the payoff line without a corner.

This is called smooth pasting: at the best boundary, value and payoff agree in level and in slope. Where no formula is available, it is the extra condition that pins the boundary down. Any other boundary breaks it, and the figure shows what goes wrong.

Rule: The perpetual American put

β=2rσ2,S∗=βK1+βS≤S∗: V=K−SS≥S∗: V=(K−S∗)(SS∗)−β\begin{gathered} \beta = \frac{2r}{\sigma^2}, \quad S^* = \frac{\beta K}{1 + \beta} \\[6pt] S \le S^*\text{: } V = K - S \\[6pt] S \ge S^*\text{: } V = (K - S^*)\left(\frac{S}{S^*}\right)^{-\beta} \end{gathered}

rr and σ\sigma are yearly decimals. Exercise the first time the price falls to S∗S^*; at S∗S^* the value meets the payoff with slope −1-1.

The perpetual put's value and its payoff, then the value minus the payoff for three exercise prices. Exercising at 50 is worth less than exercising at once just above 50. Exercising at 70 leaves a corner and less value; 60 touches the payoff smoothly.

Exercising at 50 fails in a telling way. Just above 50 its value is below the payoff: at S=55S = 55 it gives 43.3392, while exercising there pays 45. A holder following that rule would do better to exercise early, so the rule cannot be best.

Try it

value_at(S, b) is the rule "exercise when the price first falls to b". The loop rebuilds the table.

A grid of boundaries from 30 to 90 in steps of 0.01 finds the best at 60. The last line prints the formula's S∗S^* and the slope V′(S∗)V'(S^*).

⌘/Ctrl + Enter runs the cell

The value and the exercise rule

For the shared inputs, V(S)=40(S60)−1.5V(S) = 40\left(\frac{S}{60}\right)^{-1.5} above 60:

stock SS406080100120150200
value V(S)V(S)604025.980818.590314.142110.11936.5727
payoff now6040200000

At S=100S = 100 the put is worth 18.5903, though exercising now would pay nothing. The factor (10060)−1.5=0.464758\left(\frac{100}{60}\right)^{-1.5} = 0.464758 has a reading: it is the value today of $1 paid the first time the stock falls to 60. So the put is worth 40 such dollars.

Below the boundary, use the payoff, not the formula. At S=55S = 55 the formula gives 40(5560)−1.5=45.576740\left(\frac{55}{60}\right)^{-1.5} = 45.5767, but the holder exercises at once and gets 45. The formula only holds where holding is best, for S≥60S \ge 60.

Try it

perpetual_put is the rule box. The loop prints the table, value against payoff.

The last lines are the formula misused at 55, the true value there, and the discount factor (10060)−1.5\left(\frac{100}{60}\right)^{-1.5}.

⌘/Ctrl + Enter runs the cell
Check yourself
The stock is at $55, below the boundary of $60. What is the perpetual put worth?

Against the tree of case study 5.11.4

Case study 5.11.4 priced American puts on a binomial tree. A finite expiry is worth at most as much as no expiry, since the perpetual holder can copy any strategy of the finite one. So the tree's prices should rise towards 18.5903 as TT grows.

With 2,000 steps the tree gives:

expiry TT (years)103050100200
American put on the tree14.738417.657218.278618.541218.5736
below 18.5903 by3.85190.93310.31180.04910.0167

The first three match case study 5.11.4's table, 14.74, 17.66 and 18.28. The approach is slow: 50 years still leaves 31 cents. And a fixed number of steps gets coarser as TT grows, since Δt=Tn\Delta t = \frac{T}{n} is a tenth of a year at T=200T = 200.

A finer tree with 40,000 steps, too slow for this page, gives 18.5599 at T=100T = 100 and 18.5889 at T=200T = 200: within 0.0014 of the formula.

The tree's exercise boundary falls in the same way. With half a year left it was about 81 (case study 5.11.4). A finer tree puts it near 64 with 10 years left and near 61 with 50, closing in on 60.

Try it

american_put is case study 5.11.4's tree. It builds each node's price as S0eσΔt(2j−i)S_0e^{\sigma\sqrt{\Delta t}(2j - i)} rather than with powers of uu. For T=500T = 500 with 40,000 steps, u40,000u^{40{,}000} is about e894e^{894}, beyond the largest float.

Each line prints TT, the tree price and the gap to the perpetual value.

⌘/Ctrl + Enter runs the cell
Check yourself
The 50-year American put on the tree is worth 18.28, below the perpetual 18.59. Why below?

Solving the boundary-value problem numerically

Once S∗S^* is known, the value on S≥60S \ge 60 solves a boundary-value problem, and lesson 6.2.2's solve_bvp can check it. A grid cannot reach infinity, so a desk stops it at a large price LL and sets V(L)=0V(L) = 0 there.

That far condition is not quite right. The true value at LL is small but positive, and setting it to 0 drags the whole curve down.

far boundary LL2005001,0005,000
V(100)V(100) with V(L)=0V(L) = 016.097518.349318.547918.5896
slope at 60−1.0864-1.0864−1.0084-1.0084−1.0015-1.0015−1.0-1.0

At L=200L = 200 the value is $2.49 too low, and the slope at the boundary is no longer −1-1. Putting the true value V(1,000)=0.5879V(1{,}000) = 0.5879 at the far end instead recovers 18.5903. Case study 6.5.4 makes the same choice of a far boundary for its grid.

Try it

ode is the equation as a pair (V,V′)(V, V'), solved for V′′V''. np.geomspace spaces the grid evenly in ln⁡S\ln S, closer together near 60 where the curve bends most.

Each line prints LL, the far value, the solver's status (0 means it converged), V(100)V(100) and the slope at 60.

⌘/Ctrl + Enter runs the cell

Try it

The edge cases of the note, from the rule box. Each line prints rr, σ\sigma, β\beta, S∗S^* and V(100)V(100).

⌘/Ctrl + Enter runs the cell
Check yourself
The interest rate rises from 3% to 5%, with volatility still 20%. What happens to the perpetual put?
Exercise

A perpetual put, with dividends

Write perpetual_put(S, K, r, sigma, q=0.0). It returns the pair (value, boundary) for a perpetual American put on a stock with a continuous dividend yield q, as in case study 6.1.4.

The dividend changes the equation to 12σ2S2V′′+(r−q)SV′−rV=0\frac{1}{2}\sigma^2S^2V'' + (r - q)SV' - rV = 0, so the equation for pp no longer factors.

  • Solve 12σ2p(p−1)+(r−q)p−r=0\frac{1}{2}\sigma^2p(p - 1) + (r - q)p - r = 0 by the quadratic formula (lesson 1.2.2), and take its negative root pp. Write γ=−p\gamma = -p.
  • The same steps as above give S∗=γK1+γS^* = \frac{\gamma K}{1 + \gamma} and V(S)=(K−S∗)(SS∗)−γV(S) = (K - S^*)\left(\frac{S}{S^*}\right)^{-\gamma} for S≥S∗S \ge S^*, and K−SK - S below.
  • Raise ValueError if S, K or sigma is not positive, or if q is negative. Raise it too if r is not positive: there is then no boundary.

With q = 0 you should get 18.5903 and 60. The tests also try a dividend of 2%, which gives a rounder answer, a stock below the boundary, other inputs, and the bad inputs above.

See the tests
# The shared put of case study 6.2.4: K = 100, r = 0.03, sigma = 0.2, so beta = 1.5


def expect_value_error(call, why):
    try:
        call()
    except ValueError:
        return
    raise AssertionError(f"expected ValueError: {why}")


def test_shared_put():
    """Without dividends the put at S = 100 is worth 18.5903, with boundary 60"""
    value, boundary = perpetual_put(100, 100, 0.03, 0.2)
    expect_close(boundary, 60.0, what="boundary", rel=1e-9)
    expect_close(value, 18.590320061795605, what="value at S = 100", rel=1e-9)


def test_below_boundary():
    """Below the boundary the put is worth its payoff: 50 at S = 50"""
    value, boundary = perpetual_put(50, 100, 0.03, 0.2)
    expect_close(value, 50.0, what="value at S = 50", rel=1e-12)
    expect_close(boundary, 60.0, what="boundary", rel=1e-9)


def test_at_boundary():
    """At the boundary the value equals the payoff: 40 at S = 60"""
    value, _ = perpetual_put(60, 100, 0.03, 0.2)
    expect_close(value, 40.0, what="value at S = 60", rel=1e-9)


def test_dividend():
    """A 2% dividend yield gives p = −1: boundary 50 and value 25 at S = 100"""
    value, boundary = perpetual_put(100, 100, 0.03, 0.2, q=0.02)
    expect_close(boundary, 50.0, what="boundary with q = 0.02", rel=1e-9)
    expect_close(value, 25.0, what="value with q = 0.02", rel=1e-9)


def test_higher_rate():
    """At r = 5% the boundary rises to 71.43 and the value falls to 12.32"""
    value, boundary = perpetual_put(100, 100, 0.05, 0.2)
    expect_close(boundary, 71.42857142857142, what="boundary at r = 0.05", rel=1e-9)
    expect_close(value, 12.320032867762636, what="value at r = 0.05", rel=1e-9)


def test_other_inputs():
    """S = 120, K = 110, r = 5%, σ = 30%, q = 1%: boundary 55 and value 25.2083"""
    value, boundary = perpetual_put(120, 110, 0.05, 0.3, q=0.01)
    expect_close(boundary, 55.0, what="boundary", rel=1e-9)
    expect_close(value, 25.208333333333336, what="value", rel=1e-9)


def test_smooth_pasting():
    """Just above the boundary the value falls with slope −1, like the payoff"""
    _, boundary = perpetual_put(80, 90, 0.04, 0.25, q=0.01)
    h = 1e-6 * boundary
    slope = (perpetual_put(boundary + h, 90, 0.04, 0.25, q=0.01)[0] - (90 - boundary)) / h
    expect_close(slope, -1.0, what="slope just above the boundary", rel=1e-4)


def test_never_below_payoff():
    """The value is never below the payoff, from S = 10 to S = 300"""
    for S in [10, 30, 47, 48, 55, 70, 90, 100, 150, 300]:
        value, _ = perpetual_put(S, 90, 0.04, 0.25, q=0.01)
        assert value >= max(90 - S, 0) - 1e-12, f"value {value} at S = {S} is below the payoff {max(90 - S, 0)}"


def test_bad_inputs():
    """Non-positive S, K, σ or r, or a negative q, raise ValueError"""
    expect_value_error(lambda: perpetual_put(0, 100, 0.03, 0.2), "S must be positive")
    expect_value_error(lambda: perpetual_put(100, -5, 0.03, 0.2), "K must be positive")
    expect_value_error(lambda: perpetual_put(100, 100, 0.03, 0), "sigma must be positive")
    expect_value_error(lambda: perpetual_put(100, 100, 0.0, 0.2), "with r = 0 there is no exercise boundary")
    expect_value_error(lambda: perpetual_put(100, 100, -0.01, 0.2), "with r < 0 there is no exercise boundary")
    expect_value_error(lambda: perpetual_put(100, 100, 0.03, 0.2, q=-0.01), "q cannot be negative")

Summary card

  • With no expiry the put's value depends on SS only, and the Black–Scholes equation becomes 12σ2S2V′′+rSV′−rV=0\frac{1}{2}\sigma^2S^2V'' + rSV' - rV = 0: an equidimensional equation.
  • Trying V=SpV = S^p gives (p−1)(p+β)=0(p - 1)(p + \beta) = 0 with β=2rσ2\beta = \frac{2r}{\sigma^2}, so V=AS+BS−βV = AS + BS^{-\beta}. V→0V \to 0 as S→∞S \to \infty removes ASAS.
  • V(S∗)=K−S∗V(S^*) = K - S^* at the exercise boundary; the best S∗S^* is βK1+β\frac{\beta K}{1 + \beta}, where the value meets the payoff with slope −1-1 (smooth pasting).
  • For K=100K = 100, r=0.03r = 0.03, σ=0.2\sigma = 0.2: β=1.5\beta = 1.5, S∗=60S^* = 60, V(100)=40(100/60)−1.5=18.5903V(100) = 40(100/60)^{-1.5} = 18.5903. Below 60, exercise: V=K−SV = K - S.
  • The tree of case study 5.11.4 rises towards it slowly. With 2,000 steps it gives 18.2786 at 50 years and 18.5736 at 200; 40,000 steps give 18.5889 at 200.
  • Numerically, a far boundary V(L)=0V(L) = 0 biases the value low: 16.10 at L=200L = 200, 18.55 at L=1,000L = 1{,}000.

Free further reading

Optional. This lesson covers what you need; these add more examples and practice. All are free to read.