SigmaField
Mathematical Foundations for Quant Finance
0 of 256 lessons
      1. 1.1.1 What a function is: domain, range and notationConcept · 25 min
      2. 1.1.2 Transformations and piecewise functionsConcept · 30 min
      3. 1.1.3 Composition and inverse functionsConcept · 25 min
      4. 1.1.4 Practice set: functionsPractice set · 20 min
      5. 1.1.5 Case study: option payoff diagramsCase study · 30 min

Level 1, Precalculus 1.1 Functions and graphs Lesson 5 of 5

Case studyLesson 1.1.5 in Level 1, Precalculus. About 30 minutes.

Case study: option payoff diagrams

The call: a ramp moved right

A call option gives its owner the right, not the duty, to buy a stock at a fixed price KK on a fixed date. That price is the strike, and SS is the stock price on that date.

If S>KS > K, the owner buys at KK and can sell at SS, gaining S−KS - K. If S≤KS \le K, buying at KK would be pointless, so the owner lets the option lapse and gets 0. Both cases fit in one formula.

Rule: Call payoff

call(S)=max⁡(S−K, 0)\text{call}(S) = \max(S - K,\ 0)

The ramp max⁡(x,0)\max(x, 0) moved right by KK. It is flat at 0 up to the strike, then rises a dollar for each dollar the stock ends above it.

As a function (lesson 1.1.1), its domain is S≥0S \ge 0, since a share cannot be worth less than nothing. Its range is [0,∞)[0, \infty): a call never costs its owner anything at expiry, and its payoff has no upper limit. At S=KS = K both pieces give 0, so it does not matter which piece the boundary belongs to.

Try it

Evaluate the payoff at five final prices with K=100K = 100. np.maximum applies the ramp to the whole array, as in lesson 1.1.2.

The payoff is 0 up to the strike, then 10 and 20.

⌘/Ctrl + Enter runs the cell

Profit: the payoff moved down

An option is not free. The buyer pays a premium up front, say $5. The profit at expiry is the payoff minus the premium: the same ramp moved down by 5, the f(x)+kf(x) + k rule with k=−5k = -5.

The buyer breaks even where the profit is zero. That is the method of lesson 1.1.1: solve f(S)=0f(S) = 0.

Below the strike the profit is −5-5, never 0. Above it the profit is S−105S - 105, which is zero at S=105S = 105.

The same algebra answers "where must the stock end for a profit of $15?". Above the strike the profit S−105S - 105 is one-to-one, so it has an inverse (lesson 1.1.3): S=105+15=120S = 105 + 15 = 120.

Below the strike the profit is not one-to-one: every price up to 100 gives −5-5. A loss of $5 cannot tell you where the stock ended.

This ignores the interest the premium could have earned until expiry; module 1.4 handles that.

Check yourself
A call has a strike of $50 and costs $3. At what final stock price does the buyer break even?

The put: the ramp flipped

A put option gives the right to sell at KK. It pays when the stock ends below the strike: max⁡(K−S,0)\max(K - S, 0). Write it as max⁡(−(S−K),0)\max\big(-(S - K), 0\big) and it is the call's ramp with the input flipped, the f(−x)f(-x) rule from lesson 1.1.2, mirrored about S=KS = K.

The put's range is different from the call's. The stock cannot fall below 0, so the most a put can pay is KK, reached at S=0S = 0: its range is [0,K][0, K]. A put with strike 100 bought for $4 breaks even at S=96S = 96, and its largest possible profit is $96.

Payoff and profit at expiry for a call costing $5 and a put costing $4, both with strike 100. Profit is the payoff moved down by the cost, so each breaks even where its profit line crosses zero.

Selling: the payoff flipped over

Selling an option flips its payoff over the horizontal axis, the −f(x)-f(x) rule. The seller of a call receives the premium now and owes max⁡(S−K,0)\max(S - K, 0) later. With K=100K = 100 and a $5 premium, the seller's profit is 5−max⁡(S−100,0)5 - \max(S - 100, 0).

That profit is at most $5, earned whenever S≤100S \le 100. Above the strike it falls without limit: −45-45 at S=150S = 150 and −95-95 at S=200S = 200. Its range is (−∞,5](-\infty, 5], which is why desks watch sold calls closely.

A sold put has a floor: selling the $4 put loses at most $96, at S=0S = 0.

Desks record the direction as a sign. A quantity of +1+1 is an option bought (a long position) and −1-1 an option sold (a short position). The premium is cash paid (negative) for a buyer and cash received (positive) for a seller.

Strategies: add the payoffs

A position that holds several options pays the sum of their payoffs. Two classic examples follow.

A straddle buys a call and a put with the same strike. Its payoff is max⁡(S−K,0)+max⁡(K−S,0)\max(S - K, 0) + \max(K - S, 0), the ramp plus its mirror image. Lesson 1.1.2 showed that this sum is an absolute value, so the payoff is ∣S−K∣|S - K|, the distance from lesson 0.3.3.

A straddle pays when the stock moves a lot, in either direction.

The straddle costs both premiums, 5+4=95 + 4 = 9 dollars. It breaks even where ∣S−100∣=9|S - 100| = 9, which by lesson 0.3.3 means S=91S = 91 or S=109S = 109. It makes money when the stock ends further than 9 from the strike.

A bull call spread buys a call at 95 and sells a call at 105. Its payoff is a function with three pieces (lesson 1.1.2), and the pieces meet at both strikes:

P(S)={0if S≤95S−95if 95<S≤10510if S>105P(S) = \begin{cases} 0 & \text{if } S \le 95 \\ S - 95 & \text{if } 95 < S \le 105 \\ 10 & \text{if } S > 105 \end{cases}

Above 105 the sold call, a flipped ramp, cancels the bought call's rise. So the payoff is capped at 10, the gap between the strikes.

A straddle is a V: profit needs a move of more than 9 either way. A bull spread adds a ramp and a flipped ramp, so its payoff rises between the strikes and is capped at 10.

Try it

One payoff function builds every diagram. The straddle and the spread are sums of its calls and puts, with a minus sign for an option sold.

The first two printed lines match: the straddle's payoff is ∣S−100∣|S - 100|. The third line is the spread at 90, 95, 100, 105 and 110. The plot draws all four; change the legs and run it again.

⌘/Ctrl + Enter runs the cell
Check yourself
Which position has the payoff ∣S−100∣|S - 100|?

Now build positions yourself. Start from a preset, then change a side, a strike or a premium, and watch the break-evens and the largest gain and loss follow. The bull spread preset pays $8 for the 95 call and receives $3 for the 105 call, so it costs $5 and breaks even at 100. Try selling the put of the straddle instead of buying it.

Explore

Pick a strategy or build your own from up to three options. The solid line is the profit at expiry per share, the dashed line the payoff before premiums.

608010012014002040
Option 1
Option 2
Premiums
9 paid
Break-even
91 and 109
Largest profit
no limit (it keeps rising as the stock rises)
Largest loss
9

On a desk: units, conventions and bad inputs

The diagrams so far are per share. A practitioner meets a few more things before trusting a number.

  • Per share or per contract. A standard US stock option contract covers 100 shares, so its payoff is stretched by 100, the a f(x)a\,f(x) rule. A call paying $20 a share pays $2,000 a contract. Contract sizes differ between markets, so check the terms.
  • Against the return. Traders often plot a payoff against the stock's return RR, the fractional change in price. With today's price S0S_0, the final price is S=S0(1+R)S = S_0(1 + R), so the payoff becomes a composition (lesson 1.1.3). With S0=K=100S_0 = K = 100 it is max⁡(100R,0)=100max⁡(R,0)\max(100R, 0) = 100\max(R, 0), a ramp stretched by 100, with domain R≥−1R \ge -1 (a fall of 100%).
  • Bad inputs. A negative price or strike is a data error, not a market state: it lies outside the domain. Code should stop with an error rather than return a number. The same holds for a misspelt option type: reading "Call" as a put would silently mirror the diagram.
  • The sign of the quantity. A missing minus sign turns a sold option into a bought one and flips the diagram over the axis. Check one leg by hand.

A payoff diagram also has limits. It shows value at expiry only. Before then, an option's value also depends on how far the price may still move, so it is not the ramp.

Finding that value is the job of option pricing, starting with the Black–Scholes integrals of case study 2.6.5. The diagram ignores interest on the premium (module 1.4), and some options can be exercised before expiry.

Try it

The first line is one contract of the call with strike 100 at S=120S = 120.

The next two lines compare the composition call(100(1+R))\text{call}(100(1 + R)) with 100max⁡(R,0)100\max(R, 0) at returns of −20%-20\%, 0, 10% and 25%. They match.

⌘/Ctrl + Enter runs the cell
Check yourself
A trader sells a put with strike 80 for $3. What is the worst possible profit at expiry, per share?
Exercise

Call and put payoffs

Write payoff(S, K, kind) that returns the payoff at expiry of one option with strike K.

  • kind is "call" or "put". For anything else, raise ValueError.
  • S may be a single number or a NumPy array, so use np.maximum.
  • A negative stock price is outside the domain: raise ValueError if any value of S is below 0.
See the tests
import numpy as np

S = np.array([80.0, 90.0, 100.0, 110.0, 120.0])


def test_call_in_the_money():
    """A call with strike 100 pays 20 when the stock ends at 120"""
    expect_close(payoff(120, 100, "call"), 20.0, what='payoff(120, 100, "call")')


def test_call_out_of_the_money():
    """A call with strike 100 pays nothing when the stock ends at 90"""
    expect_close(payoff(90, 100, "call"), 0.0, what='payoff(90, 100, "call")')


def test_put():
    """A put with strike 100 pays 100 − S below the strike and 0 above it"""
    expect_close(payoff(S, 100, "put"), [20.0, 10.0, 0.0, 0.0, 0.0], what='payoff(S, 100, "put")')


def test_call_array():
    """A call works on a whole array of final prices"""
    expect_close(payoff(S, 100, "call"), [0.0, 0.0, 0.0, 10.0, 20.0], what='payoff(S, 100, "call")')


def test_put_call_difference():
    """Call minus put with the same strike is S − K"""
    expect_close(payoff(S, 95, "call") - payoff(S, 95, "put"), S - 95, what="call − put")


def test_unknown_kind():
    """An unknown kind raises ValueError"""
    try:
        payoff(100, 100, "swap")
    except ValueError:
        return
    raise AssertionError('expected ValueError for kind="swap"')


def test_negative_price():
    """A negative stock price raises ValueError"""
    try:
        payoff(np.array([90.0, -5.0]), 100, "call")
    except ValueError:
        return
    raise AssertionError("expected ValueError for a stock price of −5")
Exercise

Any strategy from its legs

Write strategy_payoff(S, legs). Each leg is a tuple (kind, K, quantity): quantity is positive for options bought and negative for options sold. Return the total payoff: the sum over legs of quantity times that option's payoff.

The starter gives you ramp(x), which is np.maximum(x, 0). A call is ramp(S - K) and a put is ramp(K - S).

Raise ValueError for any other kind. The tests build a straddle, a bull spread and a sold call.

See the tests
import numpy as np

S = np.array([80.0, 90.0, 100.0, 110.0, 120.0])


def test_single_call():
    """One call bought is just the call's payoff"""
    expect_close(strategy_payoff(S, [("call", 100, 1)]), [0.0, 0.0, 0.0, 10.0, 20.0], what="one call")


def test_straddle():
    """A call and a put with strike 100 pay |S − 100|"""
    legs = [("call", 100, 1), ("put", 100, 1)]
    expect_close(strategy_payoff(S, legs), np.abs(S - 100), what="straddle")


def test_bull_spread():
    """Buy the 95 call, sell the 105 call: the payoff is capped at 10"""
    legs = [("call", 95, 1), ("call", 105, -1)]
    expect_close(strategy_payoff(S, legs), [0.0, 0.0, 5.0, 10.0, 10.0], what="bull spread 95/105")


def test_sold_call():
    """Selling a call flips its payoff: −max(S − 100, 0)"""
    expect_close(strategy_payoff(S, [("call", 100, -1)]), [0.0, 0.0, 0.0, -10.0, -20.0], what="one call sold")


def test_quantity():
    """Two puts pay twice as much as one"""
    expect_close(strategy_payoff(S, [("put", 100, 2)]), [40.0, 20.0, 0.0, 0.0, 0.0], what="two puts")


def test_no_legs():
    """No legs at all pay nothing, at every price"""
    expect_close(strategy_payoff(S, []), np.zeros(5), what="no legs")


def test_unknown_kind():
    """A leg with an unknown kind raises ValueError instead of being read as a put"""
    try:
        strategy_payoff(S, [("Call", 100, 1)])
    except ValueError:
        return
    raise AssertionError('expected ValueError for kind="Call" (a capital C is a typo, not a put)')

Summary card

  • Call payoff max⁡(S−K,0)\max(S - K, 0): the ramp moved right by the strike, with range [0,∞)[0, \infty). Put payoff max⁡(K−S,0)\max(K - S, 0): the ramp mirrored about S=KS = K, with range [0,K][0, K].
  • Profit is payoff minus premium, a downward shift. A call breaks even at S=K+premiumS = K + \text{premium}; a put at S=K−premiumS = K - \text{premium}.
  • Selling an option flips its payoff over the horizontal axis. A sold call can lose without limit.
  • A strategy's payoff is the sum of its legs, quantity times payoff. Straddle: ∣S−K∣|S - K|. Bull call spread: a ramp capped at the gap between the strikes.
  • Check units (per share or per contract), signs (bought or sold), and inputs (no negative prices, no unknown option types). A payoff diagram shows value at expiry only.

Free further reading

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