A put that never expires
A put gives the right to sell a stock at the strike . Exercised when the stock price is , it pays ; it is worth exercising only when . 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 , interest rate (continuous) and volatility , both yearly decimals. The stock starts at 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, .
The equation
For an option whose value depends on the price and the time, the Black–Scholes equation holds wherever the holder keeps the option:
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 does not depend on , so the first term is 0 (case study 6.3.4 notes this too). The partial derivatives (lesson 4.1.2) become ordinary ones:
That is the equidimensional equation of lesson 6.2.2, with , , and .
Its terms all have the same units. and are per year and is in dollars; is in dollars per dollar of , and in dollars per dollar squared. So each term is in dollars per year.
Trying
Lesson 6.2.2's trial turns the equation into one for :
Multiply by and write , a pure number with no units (beta). The equation becomes
So or , and the general solution is . For the inputs above, .
The solution is the stock itself: a share solves the equation. The other, , falls as the price rises, as a put's value should.
Try it
np.roots (lesson 1.2.2) solves , the equation for multiplied out.
residual puts into the left side of the equation, at , 100 and 150. The powers 1 and leave 0; the power 2 does not.
The boundary conditions
Two conditions fix and , one at each end of the range where the holder keeps the put.
Far away. As , the stock is ever less likely to fall below the strike, and the put is worth ever less: . The term grows, so , as in lesson 6.2.2's condition at infinity. That leaves .
At the exercise price. The holder exercises when the price falls to some level , the exercise boundary, and receives there. So , which gives and
Below the put is exercised at once, so there.
Which boundary?
The two conditions give a value for every choice of , so the boundary is part of the answer: this is a free-boundary problem. The holder chooses the that makes the put worth most. With the stock at 100:
| exercise at | 40 | 50 | 55 | 60 | 65 | 70 | 80 |
|---|---|---|---|---|---|---|---|
| value at | 15.1789 | 17.6777 | 18.3551 | 18.5903 | 18.3416 | 17.5699 | 14.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 depends on . Its derivative is , which is 0 when
The best boundary does not depend on today's price . So the rule is the same wherever the stock is: wait until it first falls to 60, then exercise.
Smooth pasting
At the slope of the value is . That is the slope of the payoff . 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
and are yearly decimals. Exercise the first time the price falls to ; at the value meets the payoff with slope .
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 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 and the slope .
The value and the exercise rule
For the shared inputs, above 60:
| stock | 40 | 60 | 80 | 100 | 120 | 150 | 200 |
|---|---|---|---|---|---|---|---|
| value | 60 | 40 | 25.9808 | 18.5903 | 14.1421 | 10.1193 | 6.5727 |
| payoff now | 60 | 40 | 20 | 0 | 0 | 0 | 0 |
At the put is worth 18.5903, though exercising now would pay nothing. The factor 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 the formula gives , but the holder exercises at once and gets 45. The formula only holds where holding is best, for .
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 .
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 grows.
With 2,000 steps the tree gives:
| expiry (years) | 10 | 30 | 50 | 100 | 200 |
|---|---|---|---|---|---|
| American put on the tree | 14.7384 | 17.6572 | 18.2786 | 18.5412 | 18.5736 |
| below 18.5903 by | 3.8519 | 0.9331 | 0.3118 | 0.0491 | 0.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 grows, since is a tenth of a year at .
A finer tree with 40,000 steps, too slow for this page, gives 18.5599 at and 18.5889 at : 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 rather than with powers of . For with 40,000 steps, is about , beyond the largest float.
Each line prints , the tree price and the gap to the perpetual value.
Solving the boundary-value problem numerically
Once is known, the value on 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 and sets there.
That far condition is not quite right. The true value at is small but positive, and setting it to 0 drags the whole curve down.
| far boundary | 200 | 500 | 1,000 | 5,000 |
|---|---|---|---|---|
| with | 16.0975 | 18.3493 | 18.5479 | 18.5896 |
| slope at 60 |
At the value is $2.49 too low, and the slope at the boundary is no longer . Putting the true value 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 , solved for . np.geomspace spaces the grid evenly in , closer together near 60 where the curve bends most.
Each line prints , the far value, the solver's status (0 means it converged), and the slope at 60.
Try it
The edge cases of the note, from the rule box. Each line prints , , , and .
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 , so the equation for no longer factors.
- Solve by the quadratic formula (lesson 1.2.2), and take its negative root . Write .
- The same steps as above give and for , and below.
- Raise
ValueErrorifS,Korsigmais not positive, or ifqis negative. Raise it too ifris 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 only, and the Black–Scholes equation becomes : an equidimensional equation.
- Trying gives with , so . as removes .
- at the exercise boundary; the best is , where the value meets the payoff with slope (smooth pasting).
- For , , : , , . Below 60, exercise: .
- 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 biases the value low: 16.10 at , 18.55 at .