Skip to content

7. Source Code References

Here you can look up source code and docstrings in blackscholes.

Table of contents

Black-Scholes-Merton

Black-76

Option Structures

MixIns

Black-Scholes-Merton

Call

Bases: BlackScholesBase

Calculate (European) call option prices and Greeks with the Black-Scholes-Merton formula.

:param S: Price of underlying asset

:param K: Strike price

:param T: Time till expiration in years (1/12 indicates 1 month)

:param r: Risk-free interest rate (0.05 indicates 5%)

:param sigma: Volatility (standard deviation) of stock (0.15 indicates 15%)

:param q: Annual dividend yield (0.05 indicates 5% yield)

Source code in blackscholes/call.py
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
class BlackScholesCall(BlackScholesBase):
    """
    Calculate (European) call option prices
    and Greeks with the Black-Scholes-Merton formula.

    :param S: Price of underlying asset \n
    :param K: Strike price \n
    :param T: Time till expiration in years (1/12 indicates 1 month) \n
    :param r: Risk-free interest rate (0.05 indicates 5%) \n
    :param sigma: Volatility (standard deviation) of stock (0.15 indicates 15%) \n
    :param q: Annual dividend yield (0.05 indicates 5% yield)
    """

    def __init__(
        self, S: float, K: float, T: float, r: float, sigma: float, q: float = 0.0
    ):
        super().__init__(S=S, K=K, T=T, r=r, sigma=sigma, q=q)

    def price(self) -> float:
        """Fair value of Black-Scholes call option."""
        return (
            self.S * exp(-self.q * self.T) * self._cdf(self._d1)
            - self._cdf(self._d2) * exp(-self.r * self.T) * self.K
        )

    def delta(self) -> float:
        """Rate of change in option price
        with respect to the forward price (1st derivative).
        Note that this is the forward delta.
        For the spot delta, use `spot_delta`.
        """
        return exp(-self.q * self.T) * self._cdf(self._d1)

    def spot_delta(self) -> float:
        """
        Delta discounted for interest rates.
        For the forward delta, use `delta`.
        """
        return exp((self.r - self.q) * self.T) * self._cdf(self._d1)

    def dual_delta(self) -> float:
        """1st derivative in option price
        with respect to strike price.
        """
        return exp(-self.r * self.T) * self._cdf(self._d2)

    def theta(self) -> float:
        """Rate of change in option price
        with respect to time (i.e. time decay).
        """
        return (
            (-exp(-self.q * self.T) * self.S * self._pdf(self._d1) * self.sigma)
            / (2 * sqrt(self.T))
            - (self.r * self.K * exp(-self.r * self.T) * self._cdf(self._d2))
            + self.q * self.S * exp(-self.q * self.T) * self._cdf(self._d1)
        )

    def rho(self) -> float:
        """Rate of change in option price
        with respect to the risk-free rate.
        """
        return self.K * self.T * exp(-self.r * self.T) * self._cdf(self._d2)

    def epsilon(self) -> float:
        """Change in option price with respect to underlying dividend yield. \n
        Also known as psi."""
        return -self.S * self.T * exp(-self.q * self.T) * self._cdf(self._d1)

    def charm(self) -> float:
        """Rate of change of delta over time (also known as delta decay)."""
        return self.q * exp(-self.q * self.T) * self._cdf(self._d1) - exp(
            -self.q * self.T
        ) * self._pdf(self._d1) * (
            2.0 * (self.r - self.q) * self.T - self._d2 * self.sigma * sqrt(self.T)
        ) / (
            2.0 * self.T * self.sigma * sqrt(self.T)
        )

    def in_the_money(self) -> float:
        """Naive Probability that call option will be in the money at maturity."""
        return self._cdf(self._d2)

charm()

Rate of change of delta over time (also known as delta decay).

Source code in blackscholes/call.py
74
75
76
77
78
79
80
81
82
def charm(self) -> float:
    """Rate of change of delta over time (also known as delta decay)."""
    return self.q * exp(-self.q * self.T) * self._cdf(self._d1) - exp(
        -self.q * self.T
    ) * self._pdf(self._d1) * (
        2.0 * (self.r - self.q) * self.T - self._d2 * self.sigma * sqrt(self.T)
    ) / (
        2.0 * self.T * self.sigma * sqrt(self.T)
    )

delta()

Rate of change in option price with respect to the forward price (1st derivative). Note that this is the forward delta. For the spot delta, use spot_delta.

Source code in blackscholes/call.py
31
32
33
34
35
36
37
def delta(self) -> float:
    """Rate of change in option price
    with respect to the forward price (1st derivative).
    Note that this is the forward delta.
    For the spot delta, use `spot_delta`.
    """
    return exp(-self.q * self.T) * self._cdf(self._d1)

dual_delta()

1st derivative in option price with respect to strike price.

Source code in blackscholes/call.py
46
47
48
49
50
def dual_delta(self) -> float:
    """1st derivative in option price
    with respect to strike price.
    """
    return exp(-self.r * self.T) * self._cdf(self._d2)

epsilon()

Change in option price with respect to underlying dividend yield.

Also known as psi.

Source code in blackscholes/call.py
69
70
71
72
def epsilon(self) -> float:
    """Change in option price with respect to underlying dividend yield. \n
    Also known as psi."""
    return -self.S * self.T * exp(-self.q * self.T) * self._cdf(self._d1)

in_the_money()

Naive Probability that call option will be in the money at maturity.

Source code in blackscholes/call.py
84
85
86
def in_the_money(self) -> float:
    """Naive Probability that call option will be in the money at maturity."""
    return self._cdf(self._d2)

price()

Fair value of Black-Scholes call option.

Source code in blackscholes/call.py
24
25
26
27
28
29
def price(self) -> float:
    """Fair value of Black-Scholes call option."""
    return (
        self.S * exp(-self.q * self.T) * self._cdf(self._d1)
        - self._cdf(self._d2) * exp(-self.r * self.T) * self.K
    )

rho()

Rate of change in option price with respect to the risk-free rate.

Source code in blackscholes/call.py
63
64
65
66
67
def rho(self) -> float:
    """Rate of change in option price
    with respect to the risk-free rate.
    """
    return self.K * self.T * exp(-self.r * self.T) * self._cdf(self._d2)

spot_delta()

Delta discounted for interest rates. For the forward delta, use delta.

Source code in blackscholes/call.py
39
40
41
42
43
44
def spot_delta(self) -> float:
    """
    Delta discounted for interest rates.
    For the forward delta, use `delta`.
    """
    return exp((self.r - self.q) * self.T) * self._cdf(self._d1)

theta()

Rate of change in option price with respect to time (i.e. time decay).

Source code in blackscholes/call.py
52
53
54
55
56
57
58
59
60
61
def theta(self) -> float:
    """Rate of change in option price
    with respect to time (i.e. time decay).
    """
    return (
        (-exp(-self.q * self.T) * self.S * self._pdf(self._d1) * self.sigma)
        / (2 * sqrt(self.T))
        - (self.r * self.K * exp(-self.r * self.T) * self._cdf(self._d2))
        + self.q * self.S * exp(-self.q * self.T) * self._cdf(self._d1)
    )

Put

Bases: BlackScholesBase

Class to calculate (European) call option prices and Greeks with the Black-Scholes-Merton formula.

:param S: Price of underlying asset

:param K: Strike price

:param T: Time till expiration in years (1/12 indicates 1 month)

:param r: Risk-free interest rate (0.05 indicates 5%)

:param sigma: Volatility (standard deviation) of stock (0.15 indicates 15%)

:param q: Annual dividend yield (0.05 indicates 5% yield)

Source code in blackscholes/put.py
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
class BlackScholesPut(BlackScholesBase):
    """
    Class to calculate (European) call option prices
    and Greeks with the Black-Scholes-Merton formula.

    :param S: Price of underlying asset \n
    :param K: Strike price \n
    :param T: Time till expiration in years (1/12 indicates 1 month) \n
    :param r: Risk-free interest rate (0.05 indicates 5%) \n
    :param sigma: Volatility (standard deviation) of stock (0.15 indicates 15%) \n
    :param q: Annual dividend yield (0.05 indicates 5% yield)
    """

    def __init__(
        self, S: float, K: float, T: float, r: float, sigma: float, q: float = 0.0
    ):
        super().__init__(S=S, K=K, T=T, r=r, sigma=sigma, q=q)

    def price(self) -> float:
        """Fair value of a Black-Scholes put option."""
        return self._cdf(-self._d2) * self.K * exp(-self.r * self.T) - self.S * exp(
            -self.q * self.T
        ) * self._cdf(-self._d1)

    def delta(self) -> float:
        """
        Rate of change in option price
        with respect to the forward price (1st derivative).
        Note that this is the spot delta.
        For the forward delta, use `forward_delta`.
        """
        return exp(-self.q * self.T) * (self._cdf(self._d1) - 1)

    def spot_delta(self) -> float:
        """
        Delta discounted for interest rates.
        For the forward delta, use `delta`.
        """
        return exp((self.r - self.q) * self.T) * (self._cdf(self._d1) - 1)

    def dual_delta(self) -> float:
        """1st derivative in option price
        with respect to strike price.
        """
        return exp(-self.r * self.T) * self._cdf(-self._d2)

    def theta(self) -> float:
        """Rate of change in option price
        with respect to time (i.e. time decay).
        """
        return (
            (-exp(self.q * self.T) * self.S * self._pdf(self._d1) * self.sigma)
            / (2.0 * sqrt(self.T))
        ) + (
            self.r * self.K * exp(-self.r * self.T) * self._cdf(-self._d2)
            - self.q * self.S * exp(-self.q * self.T) * self._cdf(-self._d1)
        )

    def rho(self) -> float:
        """Rate of change in option price
        with respect to the risk-free rate.
        """
        return -self.K * self.T * exp(-self.r * self.T) * self._cdf(-self._d2)

    def epsilon(self) -> float:
        """Change in option price with respect to underlying dividend yield. \n
        Also known as psi."""
        return self.S * self.T * exp(-self.q * self.T) * self._cdf(-self._d1)

    def charm(self) -> float:
        """Rate of change of delta over time (also known as delta decay)."""
        return -self.q * exp(-self.q * self.T) * self._cdf(-self._d1) - exp(
            -self.q * self.T
        ) * self._pdf(self._d1) * (
            2.0 * (self.r - self.q) * self.T - self._d2 * self.sigma * sqrt(self.T)
        ) / (
            2.0 * self.T * self.sigma * sqrt(self.T)
        )

    def in_the_money(self) -> float:
        """Naive Probability that put option will be in the money at maturity."""
        return 1.0 - self._cdf(self._d2)

charm()

Rate of change of delta over time (also known as delta decay).

Source code in blackscholes/put.py
75
76
77
78
79
80
81
82
83
def charm(self) -> float:
    """Rate of change of delta over time (also known as delta decay)."""
    return -self.q * exp(-self.q * self.T) * self._cdf(-self._d1) - exp(
        -self.q * self.T
    ) * self._pdf(self._d1) * (
        2.0 * (self.r - self.q) * self.T - self._d2 * self.sigma * sqrt(self.T)
    ) / (
        2.0 * self.T * self.sigma * sqrt(self.T)
    )

delta()

Rate of change in option price with respect to the forward price (1st derivative). Note that this is the spot delta. For the forward delta, use forward_delta.

Source code in blackscholes/put.py
30
31
32
33
34
35
36
37
def delta(self) -> float:
    """
    Rate of change in option price
    with respect to the forward price (1st derivative).
    Note that this is the spot delta.
    For the forward delta, use `forward_delta`.
    """
    return exp(-self.q * self.T) * (self._cdf(self._d1) - 1)

dual_delta()

1st derivative in option price with respect to strike price.

Source code in blackscholes/put.py
46
47
48
49
50
def dual_delta(self) -> float:
    """1st derivative in option price
    with respect to strike price.
    """
    return exp(-self.r * self.T) * self._cdf(-self._d2)

epsilon()

Change in option price with respect to underlying dividend yield.

Also known as psi.

Source code in blackscholes/put.py
70
71
72
73
def epsilon(self) -> float:
    """Change in option price with respect to underlying dividend yield. \n
    Also known as psi."""
    return self.S * self.T * exp(-self.q * self.T) * self._cdf(-self._d1)

in_the_money()

Naive Probability that put option will be in the money at maturity.

Source code in blackscholes/put.py
85
86
87
def in_the_money(self) -> float:
    """Naive Probability that put option will be in the money at maturity."""
    return 1.0 - self._cdf(self._d2)

price()

Fair value of a Black-Scholes put option.

Source code in blackscholes/put.py
24
25
26
27
28
def price(self) -> float:
    """Fair value of a Black-Scholes put option."""
    return self._cdf(-self._d2) * self.K * exp(-self.r * self.T) - self.S * exp(
        -self.q * self.T
    ) * self._cdf(-self._d1)

rho()

Rate of change in option price with respect to the risk-free rate.

Source code in blackscholes/put.py
64
65
66
67
68
def rho(self) -> float:
    """Rate of change in option price
    with respect to the risk-free rate.
    """
    return -self.K * self.T * exp(-self.r * self.T) * self._cdf(-self._d2)

spot_delta()

Delta discounted for interest rates. For the forward delta, use delta.

Source code in blackscholes/put.py
39
40
41
42
43
44
def spot_delta(self) -> float:
    """
    Delta discounted for interest rates.
    For the forward delta, use `delta`.
    """
    return exp((self.r - self.q) * self.T) * (self._cdf(self._d1) - 1)

theta()

Rate of change in option price with respect to time (i.e. time decay).

Source code in blackscholes/put.py
52
53
54
55
56
57
58
59
60
61
62
def theta(self) -> float:
    """Rate of change in option price
    with respect to time (i.e. time decay).
    """
    return (
        (-exp(self.q * self.T) * self.S * self._pdf(self._d1) * self.sigma)
        / (2.0 * sqrt(self.T))
    ) + (
        self.r * self.K * exp(-self.r * self.T) * self._cdf(-self._d2)
        - self.q * self.S * exp(-self.q * self.T) * self._cdf(-self._d1)
    )

Base class

Bases: ABC, StandardNormalMixin

Base functionality to calculate (European) prices and Greeks with the Black-Scholes-Merton formula.

:param S: Price of underlying asset

:param K: Strike price

:param T: Time till expiration in years (1/12 indicates 1 month)

:param r: Risk-free interest rate (0.05 indicates 5%)

:param sigma: Volatility (standard deviation) of stock (0.15 indicates 15%)

:param q: Annual dividend yield (0.05 indicates 5% yield)

Source code in blackscholes/base.py
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
class BlackScholesBase(ABC, StandardNormalMixin):
    """
    Base functionality to calculate (European) prices
    and Greeks with the Black-Scholes-Merton formula.

    :param S: Price of underlying asset \n
    :param K: Strike price \n
    :param T: Time till expiration in years (1/12 indicates 1 month) \n
    :param r: Risk-free interest rate (0.05 indicates 5%) \n
    :param sigma: Volatility (standard deviation) of stock (0.15 indicates 15%) \n
    :param q: Annual dividend yield (0.05 indicates 5% yield)
    """

    def __init__(self, S: float, K: float, T: float, r: float, sigma: float, q: float):
        # Parameter checks
        assert S > 0.0, f"Asset price (S) needs to be larger than 0. Got '{S}'"
        assert K > 0.0, f"Strike price (K) needs to be larger than 0. Got '{K}'"
        assert T > 0.0, f"Time to maturity (T) needs to be larger than 0. Got '{T}'"
        assert (
            sigma > 0.0
        ), f"Volatility (sigma) needs to be larger than 0. Got '{sigma}'"
        assert q >= 0.0, f"Annual dividend yield (q) cannot be negative. Got '{q}'"
        self.S, self.K, self.T, self.r, self.sigma, self.q = S, K, T, r, sigma, q

    @abstractmethod
    def price(self) -> float:
        """Fair value for option."""
        ...

    @abstractmethod
    def in_the_money(self) -> float:
        """Naive probability that option will be in the money at maturity."""
        ...

    @abstractmethod
    def delta(self) -> float:
        """Rate of change in option price
        with respect to the forward price (1st derivative).
        """
        ...

    @abstractmethod
    def spot_delta(self) -> float:
        """
        Delta discounted for interest rates.
        For the forward delta, use `delta`.
        """
        ...

    @abstractmethod
    def dual_delta(self) -> float:
        """1st derivative of option price with respect to the strike price."""
        ...

    def gamma(self) -> float:
        """
        Rate of change in delta with respect to the underlying asset price (2nd derivative).
        """
        return (
            exp(-self.q * self.T)
            * self._pdf(self._d1)
            / (self.S * self.sigma * sqrt(self.T))
        )

    def dual_gamma(self) -> float:
        """
        Rate of change in delta with respect to the strike price (2nd derivative).
        """
        return (
            exp(-self.r * self.T)
            * self._pdf(self._d2)
            / (self.K * self.sigma * sqrt(self.T))
        )

    def vega(self) -> float:
        """
        Rate of change in option price with respect to the volatility of the asset.
        """
        return self.S * self._pdf(self._d1) * sqrt(self.T)

    @abstractmethod
    def theta(self) -> float:
        """
        Rate of change in option price
        with respect to time (i.e. time decay).
        """
        ...

    @abstractmethod
    def epsilon(self) -> float:
        """Change in option price with respect to underlying dividend yield. \n
        Also known as psi."""
        ...

    @abstractmethod
    def rho(self) -> float:
        """Rate of change in option price
        with respect to the risk-free rate.
        """
        ...

    def lambda_greek(self) -> float:
        """Percentage change in option value per %
        change in asset price. Also called gearing.
        """
        return self.delta() * self.S / self.price()

    def vanna(self) -> float:
        """Sensitivity of delta with respect to change in volatility."""
        return -self._pdf(self._d1) * self._d2 / self.sigma

    @abstractmethod
    def charm(self) -> float:
        """Rate of change of delta over time (also known as delta decay)."""
        ...

    def vomma(self) -> float:
        """2nd order sensitivity to volatility."""
        return self.vega() * self._d1 * self._d2 / self.sigma

    def veta(self) -> float:
        """Rate of change in `vega` with respect to time."""
        return (
            -self.S
            * exp(-self.q * self.T)
            * self._pdf(self._d1)
            * sqrt(self.T)
            * (
                self.q
                + (self.r - self.q) * self._d1 / (self.sigma * sqrt(self.T))
                - (1.0 + self._d1 * self._d2) / (2.0 * self.T)
            )
        )

    def phi(self) -> float:
        """2nd order partial derivative with respect to strike price. \n
        Phi is used in the Breeden-Litzenberger formula. \n
        Breeden-Litzenberger uses quoted option prices
        to estimate risk-neutral probabilities.
        """
        sigma2 = self.sigma**2
        exp_factor = (
            -1.0
            / (2.0 * sigma2 * self.T)
            * (log(self.K / self.S) - ((self.r - self.q) - 0.5 * sigma2) * self.T) ** 2
        )
        return (
            exp(-self.r * self.T)
            * (1.0 / self.K)
            * (1.0 / sqrt(2.0 * pi * sigma2 * self.T))
            * exp(exp_factor)
        )

    def speed(self) -> float:
        """Rate of change in Gamma with respect to change in the underlying price."""
        return -self.gamma() / self.S * (self._d1 / (self.sigma * sqrt(self.T)) + 1.0)

    def zomma(self) -> float:
        """Rate of change of gamma with respect to changes in volatility."""
        return self.gamma() * ((self._d1 * self._d2 - 1.0) / self.sigma)

    def color(self) -> float:
        """Rate of change of gamma over time."""
        return (
            -exp(-self.q * self.T)
            * self._pdf(self._d1)
            / (2.0 * self.S * self.T * self.sigma * sqrt(self.T))
            * (
                2.0 * self.q * self.T
                + 1.0
                + (
                    2.0 * (self.r - self.q) * self.T
                    - self._d2 * self.sigma * sqrt(self.T)
                )
                / (self.sigma * sqrt(self.T))
                * self._d1
            )
        )

    def ultima(self) -> float:
        """Sensitivity of vomma with respect to change in volatility. \n
        3rd order derivative of option value to volatility.
        """
        d1d2 = self._d1 * self._d2
        return (
            -self.vega()
            / self.sigma**2
            * (d1d2 * (1.0 - d1d2) + self._d1**2 + self._d2**2)
        )

    def alpha(self) -> float:
        """Theta to gamma ratio. Also called "gamma rent".
        More info: "Dynamic Hedging" by Nassim Taleb, p. 178-181.
        """
        return abs(self.theta()) / (self.gamma() + 1e-9)

    def get_core_greeks(self) -> Dict[str, float]:
        """
        Get the top 5 most well known Greeks.
        1. Delta
        2. Gamma
        3. Vega
        4. Theta
        5. Rho
        """
        return {
            "delta": self.delta(),
            "gamma": self.gamma(),
            "vega": self.vega(),
            "theta": self.theta(),
            "rho": self.rho(),
        }

    def get_itm_proxies(self) -> Dict[str, float]:
        """Get multiple ways of calculating probability
        of option being in the money.
        """
        return {"in_the_money": self.in_the_money(), "dual_delta": self.dual_delta()}

    def get_all_greeks(self) -> Dict[str, float]:
        """Retrieve all Greeks for the Black-Scholes-Merton model
        implemented as a dictionary."""
        return {
            "delta": self.delta(),
            "spot_delta": self.spot_delta(),
            "gamma": self.gamma(),
            "vega": self.vega(),
            "theta": self.theta(),
            "epsilon": self.epsilon(),
            "rho": self.rho(),
            "lambda_greek": self.lambda_greek(),
            "vanna": self.vanna(),
            "charm": self.charm(),
            "vomma": self.vomma(),
            "veta": self.veta(),
            "phi": self.phi(),
            "speed": self.speed(),
            "zomma": self.zomma(),
            "color": self.color(),
            "ultima": self.ultima(),
            "dual_delta": self.dual_delta(),
            "dual_gamma": self.dual_gamma(),
            "alpha": self.alpha(),
        }

    @property
    def _d1(self) -> float:
        """1st probability factor that acts as a multiplication factor for stock prices."""
        return (1.0 / (self.sigma * sqrt(self.T))) * (
            log(self.S / self.K) + (self.r - self.q + 0.5 * self.sigma**2) * self.T
        )

    @property
    def _d2(self) -> float:
        """2nd probability parameter that acts as a multiplication factor for discounting."""
        return self._d1 - self.sigma * sqrt(self.T)

alpha()

Theta to gamma ratio. Also called "gamma rent". More info: "Dynamic Hedging" by Nassim Taleb, p. 178-181.

Source code in blackscholes/base.py
212
213
214
215
216
def alpha(self) -> float:
    """Theta to gamma ratio. Also called "gamma rent".
    More info: "Dynamic Hedging" by Nassim Taleb, p. 178-181.
    """
    return abs(self.theta()) / (self.gamma() + 1e-9)

charm() abstractmethod

Rate of change of delta over time (also known as delta decay).

Source code in blackscholes/base.py
133
134
135
136
@abstractmethod
def charm(self) -> float:
    """Rate of change of delta over time (also known as delta decay)."""
    ...

color()

Rate of change of gamma over time.

Source code in blackscholes/base.py
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
def color(self) -> float:
    """Rate of change of gamma over time."""
    return (
        -exp(-self.q * self.T)
        * self._pdf(self._d1)
        / (2.0 * self.S * self.T * self.sigma * sqrt(self.T))
        * (
            2.0 * self.q * self.T
            + 1.0
            + (
                2.0 * (self.r - self.q) * self.T
                - self._d2 * self.sigma * sqrt(self.T)
            )
            / (self.sigma * sqrt(self.T))
            * self._d1
        )
    )

delta() abstractmethod

Rate of change in option price with respect to the forward price (1st derivative).

Source code in blackscholes/base.py
56
57
58
59
60
61
@abstractmethod
def delta(self) -> float:
    """Rate of change in option price
    with respect to the forward price (1st derivative).
    """
    ...

dual_delta() abstractmethod

1st derivative of option price with respect to the strike price.

Source code in blackscholes/base.py
71
72
73
74
@abstractmethod
def dual_delta(self) -> float:
    """1st derivative of option price with respect to the strike price."""
    ...

dual_gamma()

Rate of change in delta with respect to the strike price (2nd derivative).

Source code in blackscholes/base.py
86
87
88
89
90
91
92
93
94
def dual_gamma(self) -> float:
    """
    Rate of change in delta with respect to the strike price (2nd derivative).
    """
    return (
        exp(-self.r * self.T)
        * self._pdf(self._d2)
        / (self.K * self.sigma * sqrt(self.T))
    )

epsilon() abstractmethod

Change in option price with respect to underlying dividend yield.

Also known as psi.

Source code in blackscholes/base.py
110
111
112
113
114
@abstractmethod
def epsilon(self) -> float:
    """Change in option price with respect to underlying dividend yield. \n
    Also known as psi."""
    ...

gamma()

Rate of change in delta with respect to the underlying asset price (2nd derivative).

Source code in blackscholes/base.py
76
77
78
79
80
81
82
83
84
def gamma(self) -> float:
    """
    Rate of change in delta with respect to the underlying asset price (2nd derivative).
    """
    return (
        exp(-self.q * self.T)
        * self._pdf(self._d1)
        / (self.S * self.sigma * sqrt(self.T))
    )

get_all_greeks()

Retrieve all Greeks for the Black-Scholes-Merton model implemented as a dictionary.

Source code in blackscholes/base.py
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
def get_all_greeks(self) -> Dict[str, float]:
    """Retrieve all Greeks for the Black-Scholes-Merton model
    implemented as a dictionary."""
    return {
        "delta": self.delta(),
        "spot_delta": self.spot_delta(),
        "gamma": self.gamma(),
        "vega": self.vega(),
        "theta": self.theta(),
        "epsilon": self.epsilon(),
        "rho": self.rho(),
        "lambda_greek": self.lambda_greek(),
        "vanna": self.vanna(),
        "charm": self.charm(),
        "vomma": self.vomma(),
        "veta": self.veta(),
        "phi": self.phi(),
        "speed": self.speed(),
        "zomma": self.zomma(),
        "color": self.color(),
        "ultima": self.ultima(),
        "dual_delta": self.dual_delta(),
        "dual_gamma": self.dual_gamma(),
        "alpha": self.alpha(),
    }

get_core_greeks()

Get the top 5 most well known Greeks. 1. Delta 2. Gamma 3. Vega 4. Theta 5. Rho

Source code in blackscholes/base.py
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
def get_core_greeks(self) -> Dict[str, float]:
    """
    Get the top 5 most well known Greeks.
    1. Delta
    2. Gamma
    3. Vega
    4. Theta
    5. Rho
    """
    return {
        "delta": self.delta(),
        "gamma": self.gamma(),
        "vega": self.vega(),
        "theta": self.theta(),
        "rho": self.rho(),
    }

get_itm_proxies()

Get multiple ways of calculating probability of option being in the money.

Source code in blackscholes/base.py
235
236
237
238
239
def get_itm_proxies(self) -> Dict[str, float]:
    """Get multiple ways of calculating probability
    of option being in the money.
    """
    return {"in_the_money": self.in_the_money(), "dual_delta": self.dual_delta()}

in_the_money() abstractmethod

Naive probability that option will be in the money at maturity.

Source code in blackscholes/base.py
51
52
53
54
@abstractmethod
def in_the_money(self) -> float:
    """Naive probability that option will be in the money at maturity."""
    ...

lambda_greek()

Percentage change in option value per % change in asset price. Also called gearing.

Source code in blackscholes/base.py
123
124
125
126
127
def lambda_greek(self) -> float:
    """Percentage change in option value per %
    change in asset price. Also called gearing.
    """
    return self.delta() * self.S / self.price()

phi()

2nd order partial derivative with respect to strike price.

Phi is used in the Breeden-Litzenberger formula.

Breeden-Litzenberger uses quoted option prices to estimate risk-neutral probabilities.

Source code in blackscholes/base.py
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
def phi(self) -> float:
    """2nd order partial derivative with respect to strike price. \n
    Phi is used in the Breeden-Litzenberger formula. \n
    Breeden-Litzenberger uses quoted option prices
    to estimate risk-neutral probabilities.
    """
    sigma2 = self.sigma**2
    exp_factor = (
        -1.0
        / (2.0 * sigma2 * self.T)
        * (log(self.K / self.S) - ((self.r - self.q) - 0.5 * sigma2) * self.T) ** 2
    )
    return (
        exp(-self.r * self.T)
        * (1.0 / self.K)
        * (1.0 / sqrt(2.0 * pi * sigma2 * self.T))
        * exp(exp_factor)
    )

price() abstractmethod

Fair value for option.

Source code in blackscholes/base.py
46
47
48
49
@abstractmethod
def price(self) -> float:
    """Fair value for option."""
    ...

rho() abstractmethod

Rate of change in option price with respect to the risk-free rate.

Source code in blackscholes/base.py
116
117
118
119
120
121
@abstractmethod
def rho(self) -> float:
    """Rate of change in option price
    with respect to the risk-free rate.
    """
    ...

speed()

Rate of change in Gamma with respect to change in the underlying price.

Source code in blackscholes/base.py
175
176
177
def speed(self) -> float:
    """Rate of change in Gamma with respect to change in the underlying price."""
    return -self.gamma() / self.S * (self._d1 / (self.sigma * sqrt(self.T)) + 1.0)

spot_delta() abstractmethod

Delta discounted for interest rates. For the forward delta, use delta.

Source code in blackscholes/base.py
63
64
65
66
67
68
69
@abstractmethod
def spot_delta(self) -> float:
    """
    Delta discounted for interest rates.
    For the forward delta, use `delta`.
    """
    ...

theta() abstractmethod

Rate of change in option price with respect to time (i.e. time decay).

Source code in blackscholes/base.py
102
103
104
105
106
107
108
@abstractmethod
def theta(self) -> float:
    """
    Rate of change in option price
    with respect to time (i.e. time decay).
    """
    ...

ultima()

Sensitivity of vomma with respect to change in volatility.

3rd order derivative of option value to volatility.

Source code in blackscholes/base.py
201
202
203
204
205
206
207
208
209
210
def ultima(self) -> float:
    """Sensitivity of vomma with respect to change in volatility. \n
    3rd order derivative of option value to volatility.
    """
    d1d2 = self._d1 * self._d2
    return (
        -self.vega()
        / self.sigma**2
        * (d1d2 * (1.0 - d1d2) + self._d1**2 + self._d2**2)
    )

vanna()

Sensitivity of delta with respect to change in volatility.

Source code in blackscholes/base.py
129
130
131
def vanna(self) -> float:
    """Sensitivity of delta with respect to change in volatility."""
    return -self._pdf(self._d1) * self._d2 / self.sigma

vega()

Rate of change in option price with respect to the volatility of the asset.

Source code in blackscholes/base.py
 96
 97
 98
 99
100
def vega(self) -> float:
    """
    Rate of change in option price with respect to the volatility of the asset.
    """
    return self.S * self._pdf(self._d1) * sqrt(self.T)

veta()

Rate of change in vega with respect to time.

Source code in blackscholes/base.py
142
143
144
145
146
147
148
149
150
151
152
153
154
def veta(self) -> float:
    """Rate of change in `vega` with respect to time."""
    return (
        -self.S
        * exp(-self.q * self.T)
        * self._pdf(self._d1)
        * sqrt(self.T)
        * (
            self.q
            + (self.r - self.q) * self._d1 / (self.sigma * sqrt(self.T))
            - (1.0 + self._d1 * self._d2) / (2.0 * self.T)
        )
    )

vomma()

2nd order sensitivity to volatility.

Source code in blackscholes/base.py
138
139
140
def vomma(self) -> float:
    """2nd order sensitivity to volatility."""
    return self.vega() * self._d1 * self._d2 / self.sigma

zomma()

Rate of change of gamma with respect to changes in volatility.

Source code in blackscholes/base.py
179
180
181
def zomma(self) -> float:
    """Rate of change of gamma with respect to changes in volatility."""
    return self.gamma() * ((self._d1 * self._d2 - 1.0) / self.sigma)

Black76

Call

Bases: Black76Base

Calculate (European) call option prices and Greeks with the Black-76 formula.

:param F: Price of underlying futures contract

:param K: Strike price

:param T: Time till expiration in years (1/12 indicates 1 month)

:param r: Risk-free interest rate (0.05 indicates 5%)

:param sigma: Volatility (standard deviation) of stock (0.15 indicates 15%)

Source code in blackscholes/call.py
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
class Black76Call(Black76Base):
    """
    Calculate (European) call option prices
    and Greeks with the Black-76 formula.

    :param F: Price of underlying futures contract \n
    :param K: Strike price \n
    :param T: Time till expiration in years (1/12 indicates 1 month) \n
    :param r: Risk-free interest rate (0.05 indicates 5%) \n
    :param sigma: Volatility (standard deviation) of stock (0.15 indicates 15%) \n
    """

    def __init__(self, F: float, K: float, T: float, r: float, sigma: float):
        super().__init__(F=F, K=K, T=T, r=r, sigma=sigma)

    def price(self) -> float:
        """Fair value of a Black-76 call option."""
        return exp(-self.r * self.T) * (
            self.F * self._cdf(self._d1) - self.K * self._cdf(self._d2)
        )

    def delta(self) -> float:
        """Rate of change in option price
        with respect to the underlying futures price (1st derivative).
        Proxy for probability of the option expiring in the money.
        """
        return exp(-self.r * self.T) * self._cdf(self._d1)

    def theta(self) -> float:
        """Rate of change in option price
        with respect to time (i.e. time decay).
        """
        return (
            -self.F
            * exp(-self.r * self.T)
            * self._pdf(self._d1)
            * self.sigma
            / (2 * sqrt(self.T))
            - self.r * self.K * exp(-self.r * self.T) * self._cdf(self._d2)
            + self.r * self.F * exp(-self.r * self.T) * self._cdf(self._d1)
        )

    def rho(self) -> float:
        """Rate of change in option price
        with respect to the risk-free rate.
        """
        return (
            -self.T
            * exp(-self.r * self.T)
            * (self.F * self._cdf(self._d1) - self.K * self._cdf(self._d2))
        )

delta()

Rate of change in option price with respect to the underlying futures price (1st derivative). Proxy for probability of the option expiring in the money.

Source code in blackscholes/call.py
110
111
112
113
114
115
def delta(self) -> float:
    """Rate of change in option price
    with respect to the underlying futures price (1st derivative).
    Proxy for probability of the option expiring in the money.
    """
    return exp(-self.r * self.T) * self._cdf(self._d1)

price()

Fair value of a Black-76 call option.

Source code in blackscholes/call.py
104
105
106
107
108
def price(self) -> float:
    """Fair value of a Black-76 call option."""
    return exp(-self.r * self.T) * (
        self.F * self._cdf(self._d1) - self.K * self._cdf(self._d2)
    )

rho()

Rate of change in option price with respect to the risk-free rate.

Source code in blackscholes/call.py
131
132
133
134
135
136
137
138
139
def rho(self) -> float:
    """Rate of change in option price
    with respect to the risk-free rate.
    """
    return (
        -self.T
        * exp(-self.r * self.T)
        * (self.F * self._cdf(self._d1) - self.K * self._cdf(self._d2))
    )

theta()

Rate of change in option price with respect to time (i.e. time decay).

Source code in blackscholes/call.py
117
118
119
120
121
122
123
124
125
126
127
128
129
def theta(self) -> float:
    """Rate of change in option price
    with respect to time (i.e. time decay).
    """
    return (
        -self.F
        * exp(-self.r * self.T)
        * self._pdf(self._d1)
        * self.sigma
        / (2 * sqrt(self.T))
        - self.r * self.K * exp(-self.r * self.T) * self._cdf(self._d2)
        + self.r * self.F * exp(-self.r * self.T) * self._cdf(self._d1)
    )

Put

Bases: Black76Base

Source code in blackscholes/put.py
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
class Black76Put(Black76Base):
    def __init__(self, F: float, K: float, T: float, r: float, sigma: float):
        super().__init__(F=F, K=K, T=T, r=r, sigma=sigma)

    def price(self) -> float:
        """Fair value of a Black-76 put option."""
        return exp(-self.r * self.T) * (
            self.K * self._cdf(-self._d2) - self.F * self._cdf(-self._d1)
        )

    def delta(self) -> float:
        """Rate of change in option price
        with respect to the underlying futures price (1st derivative).
        Proxy for probability of the option expiring in the money.
        """
        return -exp(-self.r * self.T) * self._cdf(-self._d1)

    def theta(self) -> float:
        """Rate of change in option price
        with respect to time (i.e. time decay).
        """
        return (
            -self.F
            * exp(-self.r * self.T)
            * self._pdf(self._d1)
            * self.sigma
            / (2 * sqrt(self.T))
            + self.r * self.K * exp(-self.r * self.T) * self._cdf(-self._d2)
            - self.r * self.F * exp(-self.r * self.T) * self._cdf(-self._d1)
        )

    def rho(self) -> float:
        """Rate of change in option price
        with respect to the risk-free rate.
        """
        return (
            -self.T
            * exp(-self.r * self.T)
            * (self.K * self._cdf(-self._d2) - self.F * self._cdf(-self._d1))
        )

delta()

Rate of change in option price with respect to the underlying futures price (1st derivative). Proxy for probability of the option expiring in the money.

Source code in blackscholes/put.py
100
101
102
103
104
105
def delta(self) -> float:
    """Rate of change in option price
    with respect to the underlying futures price (1st derivative).
    Proxy for probability of the option expiring in the money.
    """
    return -exp(-self.r * self.T) * self._cdf(-self._d1)

price()

Fair value of a Black-76 put option.

Source code in blackscholes/put.py
94
95
96
97
98
def price(self) -> float:
    """Fair value of a Black-76 put option."""
    return exp(-self.r * self.T) * (
        self.K * self._cdf(-self._d2) - self.F * self._cdf(-self._d1)
    )

rho()

Rate of change in option price with respect to the risk-free rate.

Source code in blackscholes/put.py
121
122
123
124
125
126
127
128
129
def rho(self) -> float:
    """Rate of change in option price
    with respect to the risk-free rate.
    """
    return (
        -self.T
        * exp(-self.r * self.T)
        * (self.K * self._cdf(-self._d2) - self.F * self._cdf(-self._d1))
    )

theta()

Rate of change in option price with respect to time (i.e. time decay).

Source code in blackscholes/put.py
107
108
109
110
111
112
113
114
115
116
117
118
119
def theta(self) -> float:
    """Rate of change in option price
    with respect to time (i.e. time decay).
    """
    return (
        -self.F
        * exp(-self.r * self.T)
        * self._pdf(self._d1)
        * self.sigma
        / (2 * sqrt(self.T))
        + self.r * self.K * exp(-self.r * self.T) * self._cdf(-self._d2)
        - self.r * self.F * exp(-self.r * self.T) * self._cdf(-self._d1)
    )

Base class

Bases: ABC, StandardNormalMixin

Base functionality to calculate (European) prices and Greeks with the Black-76 formula.

This variant of the Black-Scholes-Merton model is often used for pricing options on futures and bonds.

:param F: Futures price

:param K: Strike price

:param T: Time till expiration in years (1/12 indicates 1 month)

:param r: Risk-free interest rate (0.05 indicates 5%)

:param sigma: Volatility (standard deviation) of stock (0.15 indicates 15%)

Source code in blackscholes/base.py
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
class Black76Base(ABC, StandardNormalMixin):
    """
    Base functionality to calculate (European) prices
    and Greeks with the Black-76 formula. \n
    This variant of the Black-Scholes-Merton model is
    often used for pricing options on futures and bonds.

    :param F: Futures price \n
    :param K: Strike price \n
    :param T: Time till expiration in years (1/12 indicates 1 month) \n
    :param r: Risk-free interest rate (0.05 indicates 5%) \n
    :param sigma: Volatility (standard deviation) of stock (0.15 indicates 15%) \n
    """

    def __init__(self, F: float, K: float, T: float, r: float, sigma: float):
        # Some parameters must be positive
        for param in [F, K, T, sigma]:
            assert (
                param >= 0.0
            ), f"Some parameters cannot be negative. Got '{param}' as an argument."
        self.F, self.K, self.T, self.r, self.sigma = F, K, T, r, sigma

    @abstractmethod
    def price(self):
        """Fair value for option."""
        ...

    @abstractmethod
    def delta(self):
        """Rate of change in option price
        with respect to the futures price (1st derivative)."""
        ...

    def gamma(self) -> float:
        """
        Rate of change in delta with respect to the underlying stock price (2nd derivative).
        """
        return (
            exp(-self.r * self.T)
            * self._pdf(self._d1)
            / (self.F * self.sigma * sqrt(self.T))
        )

    def vega(self) -> float:
        """Rate of change in option price with respect to the volatility
        of underlying futures contract.
        """
        return self.F * exp(-self.r * self.T) * self._pdf(self._d1) * sqrt(self.T)

    @abstractmethod
    def theta(self) -> float:
        """
        Rate of change in option price
        with respect to time (i.e. time decay).
        """
        ...

    @abstractmethod
    def rho(self) -> float:
        """Rate of change in option price
        with respect to the risk-free rate.
        """
        ...

    def vanna(self) -> float:
        """Sensitivity of delta with respect to change in volatility."""
        return self.vega() / self.F * (1 - self._d1 / (self.sigma * sqrt(self.T)))

    def vomma(self) -> float:
        """2nd order sensitivity to volatility."""
        return self.vega() * self._d1 * self._d2 / self.sigma

    def alpha(self) -> float:
        """Theta to gamma ratio. Also called "gamma rent".
        More info: "Dynamic Hedging" by Nassim Taleb, p. 178-181.
        """
        return abs(self.theta()) / (self.gamma() + 1e-9)

    def get_core_greeks(self) -> Dict[str, float]:
        """
        Get the top 5 most well known Greeks.
        1. Delta
        2. Gamma
        3. Vega
        4. Theta
        5. Rho
        """
        return {
            "delta": self.delta(),
            "gamma": self.gamma(),
            "vega": self.vega(),
            "theta": self.theta(),
            "rho": self.rho(),
        }

    def get_all_greeks(self) -> Dict[str, float]:
        """Retrieve all Greeks for the Black76 model implemented as a dictionary."""
        return {
            "delta": self.delta(),
            "gamma": self.gamma(),
            "vega": self.vega(),
            "theta": self.theta(),
            "rho": self.rho(),
            "vanna": self.vanna(),
            "vomma": self.vomma(),
            "alpha": self.alpha(),
        }

    @property
    def _d1(self) -> float:
        """1st probability factor that acts as a multiplication factor for futures contracts."""
        return (log(self.F / self.K) + 0.5 * self.sigma**2 * self.T) / (
            self.sigma * sqrt(self.T)
        )

    @property
    def _d2(self) -> float:
        """2nd probability parameter that acts as a multiplication factor for discounting."""
        return self._d1 - self.sigma * sqrt(self.T)

alpha()

Theta to gamma ratio. Also called "gamma rent". More info: "Dynamic Hedging" by Nassim Taleb, p. 178-181.

Source code in blackscholes/base.py
352
353
354
355
356
def alpha(self) -> float:
    """Theta to gamma ratio. Also called "gamma rent".
    More info: "Dynamic Hedging" by Nassim Taleb, p. 178-181.
    """
    return abs(self.theta()) / (self.gamma() + 1e-9)

delta() abstractmethod

Rate of change in option price with respect to the futures price (1st derivative).

Source code in blackscholes/base.py
307
308
309
310
311
@abstractmethod
def delta(self):
    """Rate of change in option price
    with respect to the futures price (1st derivative)."""
    ...

gamma()

Rate of change in delta with respect to the underlying stock price (2nd derivative).

Source code in blackscholes/base.py
313
314
315
316
317
318
319
320
321
def gamma(self) -> float:
    """
    Rate of change in delta with respect to the underlying stock price (2nd derivative).
    """
    return (
        exp(-self.r * self.T)
        * self._pdf(self._d1)
        / (self.F * self.sigma * sqrt(self.T))
    )

get_all_greeks()

Retrieve all Greeks for the Black76 model implemented as a dictionary.

Source code in blackscholes/base.py
375
376
377
378
379
380
381
382
383
384
385
386
def get_all_greeks(self) -> Dict[str, float]:
    """Retrieve all Greeks for the Black76 model implemented as a dictionary."""
    return {
        "delta": self.delta(),
        "gamma": self.gamma(),
        "vega": self.vega(),
        "theta": self.theta(),
        "rho": self.rho(),
        "vanna": self.vanna(),
        "vomma": self.vomma(),
        "alpha": self.alpha(),
    }

get_core_greeks()

Get the top 5 most well known Greeks. 1. Delta 2. Gamma 3. Vega 4. Theta 5. Rho

Source code in blackscholes/base.py
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
def get_core_greeks(self) -> Dict[str, float]:
    """
    Get the top 5 most well known Greeks.
    1. Delta
    2. Gamma
    3. Vega
    4. Theta
    5. Rho
    """
    return {
        "delta": self.delta(),
        "gamma": self.gamma(),
        "vega": self.vega(),
        "theta": self.theta(),
        "rho": self.rho(),
    }

price() abstractmethod

Fair value for option.

Source code in blackscholes/base.py
302
303
304
305
@abstractmethod
def price(self):
    """Fair value for option."""
    ...

rho() abstractmethod

Rate of change in option price with respect to the risk-free rate.

Source code in blackscholes/base.py
337
338
339
340
341
342
@abstractmethod
def rho(self) -> float:
    """Rate of change in option price
    with respect to the risk-free rate.
    """
    ...

theta() abstractmethod

Rate of change in option price with respect to time (i.e. time decay).

Source code in blackscholes/base.py
329
330
331
332
333
334
335
@abstractmethod
def theta(self) -> float:
    """
    Rate of change in option price
    with respect to time (i.e. time decay).
    """
    ...

vanna()

Sensitivity of delta with respect to change in volatility.

Source code in blackscholes/base.py
344
345
346
def vanna(self) -> float:
    """Sensitivity of delta with respect to change in volatility."""
    return self.vega() / self.F * (1 - self._d1 / (self.sigma * sqrt(self.T)))

vega()

Rate of change in option price with respect to the volatility of underlying futures contract.

Source code in blackscholes/base.py
323
324
325
326
327
def vega(self) -> float:
    """Rate of change in option price with respect to the volatility
    of underlying futures contract.
    """
    return self.F * exp(-self.r * self.T) * self._pdf(self._d1) * sqrt(self.T)

vomma()

2nd order sensitivity to volatility.

Source code in blackscholes/base.py
348
349
350
def vomma(self) -> float:
    """2nd order sensitivity to volatility."""
    return self.vega() * self._d1 * self._d2 / self.sigma

Straddle

Long

Bases: BlackScholesStructureBase

Create long straddle option structure.

  • Long Straddle -> Put(K) + Call(K)

:param S: Price of underlying asset

:param K: Strike price

:param T: Time till expiration in years (1/12 indicates 1 month)

:param r: Risk-free interest rate (0.05 indicates 5%)

:param sigma: Volatility (standard deviation) of stock (0.15 indicates 15%)

:param q: Annual dividend yield (0.05 indicates 5% yield)

Source code in blackscholes/straddle.py
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
class BlackScholesStraddleLong(BlackScholesStructureBase):
    """
    Create long straddle option structure. \n
    - Long Straddle -> Put(K) + Call(K)

    :param S: Price of underlying asset \n
    :param K: Strike price \n
    :param T: Time till expiration in years (1/12 indicates 1 month) \n
    :param r: Risk-free interest rate (0.05 indicates 5%) \n
    :param sigma: Volatility (standard deviation) of stock (0.15 indicates 15%) \n
    :param q: Annual dividend yield (0.05 indicates 5% yield) \n
    """

    def __init__(
        self,
        S: float,
        K: float,
        T: float,
        r: float,
        sigma: float,
        q: float = 0.0,
    ):
        self.call1 = BlackScholesCall(S=S, K=K, T=T, r=r, sigma=sigma, q=q)
        self.put1 = BlackScholesPut(S=S, K=K, T=T, r=r, sigma=sigma, q=q)
        super().__init__()

    def _calc_attr(self, attribute_name: str) -> float:
        """
        Combines attributes from a put and call option into a long straddle. \n
        All greeks and price are combined in the same way. \n

        :param attribute_name: String name of option attribute
        pointing to a method that can be called on
        BlackScholesCall and BlackScholesPut.

        :return: Combined value according to long straddle.
        """
        put_attr = getattr(self.put1, attribute_name)
        call_attr = getattr(self.call1, attribute_name)
        return put_attr() + call_attr()

Short

Bases: BlackScholesStructureBase

Create straddle option structure.

  • Short Straddle -> -Put(K) - Call(K)

:param S: Price of underlying asset

:param K: Strike price

:param T: Time till expiration in years (1/12 indicates 1 month)

:param r: Risk-free interest rate (0.05 indicates 5%)

:param sigma: Volatility (standard deviation) of stock (0.15 indicates 15%)

:param q: Annual dividend yield (0.05 indicates 5% yield)

Source code in blackscholes/straddle.py
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
class BlackScholesStraddleShort(BlackScholesStructureBase):
    """
    Create straddle option structure. \n
    - Short Straddle -> -Put(K) - Call(K)

    :param S: Price of underlying asset \n
    :param K: Strike price \n
    :param T: Time till expiration in years (1/12 indicates 1 month) \n
    :param r: Risk-free interest rate (0.05 indicates 5%) \n
    :param sigma: Volatility (standard deviation) of stock (0.15 indicates 15%) \n
    :param q: Annual dividend yield (0.05 indicates 5% yield)
    """

    def __init__(
        self,
        S: float,
        K: float,
        T: float,
        r: float,
        sigma: float,
        q: float = 0.0,
    ):
        self.call1 = BlackScholesCall(S=S, K=K, T=T, r=r, sigma=sigma, q=q)
        self.put1 = BlackScholesPut(S=S, K=K, T=T, r=r, sigma=sigma, q=q)
        super().__init__()

    def _calc_attr(self, attribute_name: str) -> float:
        """
        Combines attributes from a put and call option into a short straddle. \n
        All greeks and price are combined in the same way. \n

        :param attribute_name: String name of option attribute
        pointing to a method that can be called on
        BlackScholesCall and BlackScholesPut.

        :return: Combined value according to short straddle.
        """
        put_attr = getattr(self.put1, attribute_name)
        call_attr = getattr(self.call1, attribute_name)
        return -put_attr() - call_attr()

Strangle

Long

Bases: BlackScholesStructureBase

Create long strangle option structure.

  • Long strangle -> Put(K1) + Call(K2)

:param S: Price of underlying asset

:param K1: Strike price for put

:param K2: Strike price for call

It must hold that K1 < K2.

:param T: Time till expiration in years (1/12 indicates 1 month)

:param r: Risk-free interest rate (0.05 indicates 5%)

:param sigma: Volatility (standard deviation) of stock (0.15 indicates 15%)

:param q: Annual dividend yield (0.05 indicates 5% yield)

Source code in blackscholes/strangle.py
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
class BlackScholesStrangleLong(BlackScholesStructureBase):
    """
    Create long strangle option structure. \n
    - Long strangle -> Put(K1) + Call(K2)

    :param S: Price of underlying asset \n
    :param K1: Strike price for put \n
    :param K2: Strike price for call \n
    It must hold that K1 < K2. \n
    :param T: Time till expiration in years (1/12 indicates 1 month) \n
    :param r: Risk-free interest rate (0.05 indicates 5%) \n
    :param sigma: Volatility (standard deviation) of stock (0.15 indicates 15%) \n
    :param q: Annual dividend yield (0.05 indicates 5% yield) \n
    """

    def __init__(
        self,
        S: float,
        K1: float,
        K2: float,
        T: float,
        r: float,
        sigma: float,
        q: float = 0.0,
    ):
        assert (
            K1 < K2
        ), f"""1st strike price should be smaller than 2nd.
        Got K1={K1}, which is not smaller than K2={K2}.
        """
        self.put1 = BlackScholesPut(S=S, K=K1, T=T, r=r, sigma=sigma, q=q)
        self.call1 = BlackScholesCall(S=S, K=K2, T=T, r=r, sigma=sigma, q=q)
        super().__init__()

    def _calc_attr(self, attribute_name: str) -> float:
        """
        Combines attributes from a put and call option into a long strangle. \n
        All greeks and price are combined in the same way.

        :param attribute_name: String name of option attribute
        pointing to a method that can be called on
        BlackScholesCall and BlackScholesPut.

        :return: Combined value according to long strangle.
        """
        put_attr = getattr(self.put1, attribute_name)
        call_attr = getattr(self.call1, attribute_name)
        return put_attr() + call_attr()

Short

Bases: BlackScholesStructureBase

Create short strangle option structure.

  • Short strangle -> -Put(K1) - Call(K2)

:param S: Price of underlying asset

:param K1: Strike price for put

:param K2: Strike price for call

It must hold that K1 < K2.

:param T: Time till expiration in years (1/12 indicates 1 month)

:param r: Risk-free interest rate (0.05 indicates 5%)

:param sigma: Volatility (standard deviation) of stock (0.15 indicates 15%)

:param q: Annual dividend yield (0.05 indicates 5% yield)

Source code in blackscholes/strangle.py
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
class BlackScholesStrangleShort(BlackScholesStructureBase):
    """
    Create short strangle option structure. \n
    - Short strangle -> -Put(K1) - Call(K2)

    :param S: Price of underlying asset \n
    :param K1: Strike price for put \n
    :param K2: Strike price for call \n
    It must hold that K1 < K2. \n
    :param T: Time till expiration in years (1/12 indicates 1 month) \n
    :param r: Risk-free interest rate (0.05 indicates 5%) \n
    :param sigma: Volatility (standard deviation) of stock (0.15 indicates 15%) \n
    :param q: Annual dividend yield (0.05 indicates 5% yield)
    """

    def __init__(
        self,
        S: float,
        K1: float,
        K2: float,
        T: float,
        r: float,
        sigma: float,
        q: float = 0.0,
    ):
        assert (
            K1 < K2
        ), f"""1st strike price should be smaller than 2nd.
        Got K1={K1}, which is not smaller than K2={K2}.
        """
        self.put1 = BlackScholesPut(S=S, K=K1, T=T, r=r, sigma=sigma, q=q)
        self.call1 = BlackScholesCall(S=S, K=K2, T=T, r=r, sigma=sigma, q=q)
        super().__init__()

    def _calc_attr(self, attribute_name: str) -> float:
        """
        Combines attributes from a put and call option into a short strangle. \n
        All greeks and price are combined in the same way.

        :param attribute_name: String name of option attribute
        pointing to a method that can be called on
        BlackScholesCall and BlackScholesPut.

        :return: Combined value according to short strangle.
        """
        put_attr = getattr(self.put1, attribute_name)
        call_attr = getattr(self.call1, attribute_name)
        return -put_attr() - call_attr()

Butterfly

Long

Bases: BlackScholesStructureBase

Create long butterfly option structure. - Long butterfly -> Call(K1) - 2 * Call(K2) + Call(K3)

:param S: Price of underlying asset

:param K1: Strike price for 1st option

:param K2: Strike price for 2nd option

:param K3: Strike price for 3rd option

It must hold that K1 < K2 < K3.

Additionally, it must hold that K2 - K1 = K3 - K2

:param T: Time till expiration in years (1/12 indicates 1 month)

:param r: Risk-free interest rate (0.05 indicates 5%)

:param sigma: Volatility (standard deviation) of stock (0.15 indicates 15%)

:param q: Annual dividend yield (0.05 indicates 5% yield)

Source code in blackscholes/butterfly.py
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
class BlackScholesButterflyLong(BlackScholesStructureBase):
    """
    Create long butterfly option structure.
    - Long butterfly -> Call(K1) - 2 * Call(K2) + Call(K3)

    :param S: Price of underlying asset \n
    :param K1: Strike price for 1st option \n
    :param K2: Strike price for 2nd option \n
    :param K3: Strike price for 3rd option \n
    It must hold that K1 < K2 < K3. \n
    Additionally, it must hold that K2 - K1 = K3 - K2 \n
    :param T: Time till expiration in years (1/12 indicates 1 month) \n
    :param r: Risk-free interest rate (0.05 indicates 5%) \n
    :param sigma: Volatility (standard deviation) of stock (0.15 indicates 15%) \n
    :param q: Annual dividend yield (0.05 indicates 5% yield)
    """

    def __init__(
        self,
        S: float,
        K1: float,
        K2: float,
        K3: float,
        T: float,
        r: float,
        sigma: float,
        q: float = 0.0,
    ):
        assert (
            K1 < K2 < K3
        ), f"""It must hold that K1 < K2 < K3.
                        Got {K1}, {K2} and {K3}.
                        """
        assert (
            K2 - K1 == K3 - K2
        ), f"""Strike price must be symmetric, so K2 - K1 = K3 - K2.
                        Got {K2}-{K1} != {K3}-{K2}.
                        """
        super().__init__()
        self.call1 = BlackScholesCall(S=S, K=K1, T=T, r=r, sigma=sigma, q=q)
        self.call2 = BlackScholesCall(S=S, K=K2, T=T, r=r, sigma=sigma, q=q)
        self.call3 = BlackScholesCall(S=S, K=K3, T=T, r=r, sigma=sigma, q=q)

    def _calc_attr(self, attribute_name: str) -> float:
        """
        Combines attributes from three call options into a long call butterfly. \n
        All greeks and price are combined in the same way.

        :param attribute_name: String name of option attribute
        pointing to a method that can be called on
        BlackScholesCall and BlackScholesPut.

        :return: Combined value according to long call butterfly.
        """
        call_attr1 = getattr(self.call1, attribute_name)
        call_attr2 = getattr(self.call2, attribute_name)
        call_attr3 = getattr(self.call3, attribute_name)
        return call_attr1() - 2 * call_attr2() + call_attr3()

Short

Bases: BlackScholesStructureBase

Create short butterfly option structure.

  • Short butterfly -> -Put(K1) + 2 * Put(K2) - Put(K3)

:param S: Price of underlying asset

:param K1: Strike price for 1st option

:param K2: Strike price for 2nd option

:param K3: Strike price for 3rd option

It must hold that K1 < K2 < K3.

Additionally, it must hold that K2 - K1 = K3 - K2

:param T: Time till expiration in years (1/12 indicates 1 month)

:param r: Risk-free interest rate (0.05 indicates 5%)

:param sigma: Volatility (standard deviation) of stock (0.15 indicates 15%)

:param q: Annual dividend yield (0.05 indicates 5% yield)

Source code in blackscholes/butterfly.py
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
class BlackScholesButterflyShort(BlackScholesStructureBase):
    """
    Create short butterfly option structure. \n
    - Short butterfly -> -Put(K1) + 2 * Put(K2) - Put(K3)

    :param S: Price of underlying asset \n
    :param K1: Strike price for 1st option \n
    :param K2: Strike price for 2nd option \n
    :param K3: Strike price for 3rd option \n
    It must hold that K1 < K2 < K3. \n
    Additionally, it must hold that K2 - K1 = K3 - K2 \n
    :param T: Time till expiration in years (1/12 indicates 1 month) \n
    :param r: Risk-free interest rate (0.05 indicates 5%) \n
    :param sigma: Volatility (standard deviation) of stock (0.15 indicates 15%) \n
    :param q: Annual dividend yield (0.05 indicates 5% yield)
    """

    def __init__(
        self,
        S: float,
        K1: float,
        K2: float,
        K3: float,
        T: float,
        r: float,
        sigma: float,
        q: float = 0.0,
    ):
        assert (
            K1 < K2 < K3
        ), f"""It must hold that K1 < K2 < K3.
                        Got {K1}, {K2} and {K3}.
                        """
        assert (
            K2 - K1 == K3 - K2
        ), f"""Strike price must be symmetric, so K2 - K1 = K3 - K2.
                        Got {K2}-{K1} != {K3}-{K2}.
                        """
        super().__init__()
        self.put1 = BlackScholesPut(S=S, K=K1, T=T, r=r, sigma=sigma, q=q)
        self.put2 = BlackScholesPut(S=S, K=K2, T=T, r=r, sigma=sigma, q=q)
        self.put3 = BlackScholesPut(S=S, K=K3, T=T, r=r, sigma=sigma, q=q)

    def _calc_attr(self, attribute_name: str) -> float:
        """
        Combines attributes from three put options into a short put butterfly. \n
        All greeks and price are combined in the same way.

        :param attribute_name: String name of option attribute
        pointing to a method that can be called on
        BlackScholesCall and BlackScholesPut.

        :return: Combined value according to short put butterfly.
        """
        put_attr1 = getattr(self.put1, attribute_name)
        put_attr2 = getattr(self.put2, attribute_name)
        put_attr3 = getattr(self.put3, attribute_name)
        return -put_attr1() + 2 * put_attr2() - put_attr3()

Iron Condor

Long

Bases: BlackScholesStructureBase

Create long iron condor option structure.

  • Long iron condor -> Put(K1) - Put(K2) - Call(K3) + Call(K4)

:param S: Price of underlying asset

:param K1: Strike price for 1st option

:param K2: Strike price for 2nd option

:param K3: Strike price for 3rd option

:param K4: Strike price for 3rd option

It must hold that K1 < K2 < K3 < K4.

Additionally, it must hold that K4 - K3 = K2 - K1

:param T: Time till expiration in years (1/12 indicates 1 month)

:param r: Risk-free interest rate (0.05 indicates 5%)

:param sigma: Volatility (standard deviation) of stock (0.15 indicates 15%)

:param q: Annual dividend yield (0.05 indicates 5% yield)

Source code in blackscholes/iron_condor.py
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
class BlackScholesIronCondorLong(BlackScholesStructureBase):
    """
    Create long iron condor option structure. \n
    - Long iron condor -> Put(K1) - Put(K2) - Call(K3) + Call(K4)

    :param S: Price of underlying asset \n
    :param K1: Strike price for 1st option \n
    :param K2: Strike price for 2nd option \n
    :param K3: Strike price for 3rd option \n
    :param K4: Strike price for 3rd option \n
    It must hold that K1 < K2 < K3 < K4. \n
    Additionally, it must hold that K4 - K3 = K2 - K1 \n
    :param T: Time till expiration in years (1/12 indicates 1 month) \n
    :param r: Risk-free interest rate (0.05 indicates 5%) \n
    :param sigma: Volatility (standard deviation) of stock (0.15 indicates 15%) \n
    :param q: Annual dividend yield (0.05 indicates 5% yield)
    """

    def __init__(
        self,
        S: float,
        K1: float,
        K2: float,
        K3: float,
        K4: float,
        T: float,
        r: float,
        sigma: float,
        q: float = 0.0,
    ):
        assert (
            K1 < K2 < K3 < K4
        ), f"""It must hold that K1 < K2 < K3 < K4.
        Got {K1}, {K2}, {K3} and {K4}.
        """
        assert (
            K4 - K3 == K2 - K1
        ), f"""Strike price must be symmetric, so K4 - K3 = K2 - K1.
        Got {K2}-{K1} != {K3}-{K2}.
        """
        super().__init__()
        self.put1 = BlackScholesPut(S=S, K=K1, T=T, r=r, sigma=sigma, q=q)
        self.put2 = BlackScholesPut(S=S, K=K2, T=T, r=r, sigma=sigma, q=q)
        self.call1 = BlackScholesCall(S=S, K=K3, T=T, r=r, sigma=sigma, q=q)
        self.call2 = BlackScholesCall(S=S, K=K4, T=T, r=r, sigma=sigma, q=q)

    def _calc_attr(self, attribute_name: str) -> float:
        """
        Combines attributes from two put and two call options into a long iron condor. \n
        All greeks and price are combined in the same way.

        :param attribute_name: String name of option attribute
        pointing to a method that can be called on
        BlackScholesCall and BlackScholesPut.

        :return: Combined value according to long iron condor.
        """
        put_attr1 = getattr(self.put1, attribute_name)
        put_attr2 = getattr(self.put2, attribute_name)
        call_attr1 = getattr(self.call1, attribute_name)
        call_attr2 = getattr(self.call2, attribute_name)
        return -put_attr1() + put_attr2() + call_attr1() - call_attr2()

Short

Bases: BlackScholesStructureBase

Create short iron condor option structure.

  • Short iron condor -> -Put(K1) + Put(K2) + Call(K3) - Call(K4)

:param S: Price of underlying asset

:param K1: Strike price for 1st option

:param K2: Strike price for 2nd option

:param K3: Strike price for 3rd option

:param K4: Strike price for 3rd option

It must hold that K1 < K2 < K3 < K4.

Additionally, it must hold that K4 - K3 = K2 - K1

:param T: Time till expiration in years (1/12 indicates 1 month)

:param r: Risk-free interest rate (0.05 indicates 5%)

:param sigma: Volatility (standard deviation) of stock (0.15 indicates 15%)

:param q: Annual dividend yield (0.05 indicates 5% yield)

Source code in blackscholes/iron_condor.py
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
class BlackScholesIronCondorShort(BlackScholesStructureBase):
    """
    Create short iron condor option structure. \n
    - Short iron condor -> -Put(K1) + Put(K2) + Call(K3) - Call(K4)

    :param S: Price of underlying asset \n
    :param K1: Strike price for 1st option \n
    :param K2: Strike price for 2nd option \n
    :param K3: Strike price for 3rd option \n
    :param K4: Strike price for 3rd option \n
    It must hold that K1 < K2 < K3 < K4. \n
    Additionally, it must hold that K4 - K3 = K2 - K1 \n
    :param T: Time till expiration in years (1/12 indicates 1 month) \n
    :param r: Risk-free interest rate (0.05 indicates 5%) \n
    :param sigma: Volatility (standard deviation) of stock (0.15 indicates 15%) \n
    :param q: Annual dividend yield (0.05 indicates 5% yield)
    """

    def __init__(
        self,
        S: float,
        K1: float,
        K2: float,
        K3: float,
        K4: float,
        T: float,
        r: float,
        sigma: float,
        q: float = 0.0,
    ):
        assert (
            K1 < K2 < K3 < K4
        ), f"""It must hold that K1 < K2 < K3 < K4.
        Got {K1}, {K2}, {K3} and {K4}.
        """
        assert (
            K4 - K3 == K2 - K1
        ), f"""Strike price must be symmetric, so K4 - K3 = K2 - K1.
        Got {K2}-{K1} != {K3}-{K2}.
        """
        super().__init__()
        self.put1 = BlackScholesPut(S=S, K=K1, T=T, r=r, sigma=sigma, q=q)
        self.put2 = BlackScholesPut(S=S, K=K2, T=T, r=r, sigma=sigma, q=q)
        self.call1 = BlackScholesCall(S=S, K=K3, T=T, r=r, sigma=sigma, q=q)
        self.call2 = BlackScholesCall(S=S, K=K4, T=T, r=r, sigma=sigma, q=q)

    def _calc_attr(self, attribute_name: str) -> float:
        """
        Combines attributes from two put and two call options into a short iron condor. \n
        All greeks and price are combined in the same way.

        :param attribute_name: String name of option attribute
        pointing to a method that can be called on
        BlackScholesCall and BlackScholesPut.

        :return: Combined value according to short iron condor.
        """
        put_attr1 = getattr(self.put1, attribute_name)
        put_attr2 = getattr(self.put2, attribute_name)
        call_attr1 = getattr(self.call1, attribute_name)
        call_attr2 = getattr(self.call2, attribute_name)
        return put_attr1() - put_attr2() - call_attr1() + call_attr2()

Spreads

Bull Spread

Bases: BlackScholesStructureBase

Create bull spread option structure.

  • Bull Spread -> Call(K1) - Call(K2)

:param S: Price of underlying asset

:param K1: Strike price for 1st call

:param K2: Strike price for 2nd call

It must hold that K1 < K2.

:param T: Time till expiration in years (1/12 indicates 1 month)

:param r: Risk-free interest rate (0.05 indicates 5%)

:param sigma: Volatility (standard deviation) of stock (0.15 indicates 15%)

:param q: Annual dividend yield (0.05 indicates 5% yield)

Source code in blackscholes/spread.py
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
class BlackScholesBullSpread(BlackScholesStructureBase):
    """
    Create bull spread option structure. \n
    - Bull Spread -> Call(K1) - Call(K2)

    :param S: Price of underlying asset \n
    :param K1: Strike price for 1st call \n
    :param K2: Strike price for 2nd call \n
    It must hold that K1 < K2. \n
    :param T: Time till expiration in years (1/12 indicates 1 month) \n
    :param r: Risk-free interest rate (0.05 indicates 5%) \n
    :param sigma: Volatility (standard deviation) of stock (0.15 indicates 15%) \n
    :param q: Annual dividend yield (0.05 indicates 5% yield) \n
    """

    def __init__(
        self,
        S: float,
        K1: float,
        K2: float,
        T: float,
        r: float,
        sigma: float,
        q: float = 0.0,
    ):
        assert (
            K1 < K2
        ), f"""1st strike price should be smaller than 2nd.
        Got K1={K1}, which is not smaller than K2={K2}.
        """
        self.call1 = BlackScholesCall(S=S, K=K1, T=T, r=r, sigma=sigma, q=q)
        self.call2 = BlackScholesCall(S=S, K=K2, T=T, r=r, sigma=sigma, q=q)
        super().__init__()

    def _calc_attr(self, attribute_name: str) -> float:
        """
        Combines attributes from two call options into a bull spread. \n
        All greeks and prices are combined in the same way.

        :param attribute_name: String name of option attribute
        pointing to a method that can be called on
        BlackScholesCall and BlackScholesPut.

        :return: Combined value according to bull spread.
        """
        call1_attr = getattr(self.call1, attribute_name)
        call2_attr = getattr(self.call2, attribute_name)
        return call1_attr() - call2_attr()

Bear Spread

Bases: BlackScholesStructureBase

Create bear spread option structure.

  • Bear Spread -> Put(K1) - Put(K2)

:param S: Price of underlying asset

:param K1: Strike price for 1st put

:param K2: Strike price for 2nd put

It must hold that K1 > K2.

:param T: Time till expiration in years (1/12 indicates 1 month)

:param r: Risk-free interest rate (0.05 indicates 5%)

:param sigma: Volatility (standard deviation) of stock (0.15 indicates 15%)

:param q: Annual dividend yield (0.05 indicates 5% yield)

Source code in blackscholes/spread.py
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
class BlackScholesBearSpread(BlackScholesStructureBase):
    """
    Create bear spread option structure. \n
    - Bear Spread -> Put(K1) - Put(K2)

    :param S: Price of underlying asset \n
    :param K1: Strike price for 1st put \n
    :param K2: Strike price for 2nd put \n
    It must hold that K1 > K2. \n
    :param T: Time till expiration in years (1/12 indicates 1 month) \n
    :param r: Risk-free interest rate (0.05 indicates 5%) \n
    :param sigma: Volatility (standard deviation) of stock (0.15 indicates 15%) \n
    :param q: Annual dividend yield (0.05 indicates 5% yield) \n
    """
    def __init__(
        self,
        S: float,
        K1: float,
        K2: float,
        T: float,
        r: float,
        sigma: float,
        q: float = 0.0,
    ):
        assert (
            K1 > K2
        ), f"""1st strike price should be larger than 2nd.
        Got K1={K1}, which is not larger than K2={K2}.
        """
        self.put1 = BlackScholesPut(S=S, K=K1, T=T, r=r, sigma=sigma, q=q)
        self.put2 = BlackScholesPut(S=S, K=K2, T=T, r=r, sigma=sigma, q=q)
        super().__init__()

    def _calc_attr(self, attribute_name: str) -> float:
        """
        Combines attributes from two put options into a bear spread. \n
        All greeks and prices are combined in the same way.

        :param attribute_name: String name of option attribute
        pointing to a method that can be called on
        BlackScholesCall and BlackScholesPut.

        :return: Combined value according to bear spread.
        """
        put1_attr = getattr(self.put1, attribute_name)
        put2_attr = getattr(self.put2, attribute_name)
        return put1_attr() - put2_attr()

Iron Butterfly

Long

Bases: BlackScholesStructureBase

Create long iron butterfly option structure.

  • Long iron butterfly -> - Put(K1) + Put(K2) + Call(K3) - Call(K4)

:param S: Price of underlying asset

:param K1: Strike price for 1st option

:param K2: Strike price for 2nd and 3rd option

:param K3: Strike price for 4th option

It must hold that K1 < K2 < K3.

Additionally, it must hold that K3 - K2 = K2 - K1 (equidistant strike prices)

:param T: Time till expiration in years (1/12 indicates 1 month)

:param r: Risk-free interest rate (0.05 indicates 5%)

:param sigma: Volatility (standard deviation) of stock (0.15 indicates 15%)

:param q: Annual dividend yield (0.05 indicates 5% yield)

Source code in blackscholes/iron_butterfly.py
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
class BlackScholesIronButterflyLong(BlackScholesStructureBase):
    """
    Create long iron butterfly option structure. \n
    - Long iron butterfly -> - Put(K1) + Put(K2) + Call(K3) - Call(K4)

    :param S: Price of underlying asset \n
    :param K1: Strike price for 1st option \n
    :param K2: Strike price for 2nd and 3rd option \n
    :param K3: Strike price for 4th option \n
    It must hold that K1 < K2 < K3. \n
    Additionally, it must hold that K3 - K2 = K2 - K1 (equidistant strike prices) \n
    :param T: Time till expiration in years (1/12 indicates 1 month) \n
    :param r: Risk-free interest rate (0.05 indicates 5%) \n
    :param sigma: Volatility (standard deviation) of stock (0.15 indicates 15%) \n
    :param q: Annual dividend yield (0.05 indicates 5% yield)
    """

    def __init__(
        self,
        S: float,
        K1: float,
        K2: float,
        K3: float,
        T: float,
        r: float,
        sigma: float,
        q: float = 0.0,
    ):
        assert (
            K1 < K2 < K3
        ), f"""It must hold that K1 < K2 < K3.
        Got {K1}, {K2}, {K3}.
        """
        assert (
            K3 - K2 == K2 - K1
        ), f"""All strike prices must be equidistant, so K4 - K3 = K3 - K2 = K2 - K1.
        Got {K3}-{K2} != {K2}-{K1}.
        """
        super().__init__()
        self.put1 = BlackScholesPut(S=S, K=K1, T=T, r=r, sigma=sigma, q=q)
        self.put2 = BlackScholesPut(S=S, K=K2, T=T, r=r, sigma=sigma, q=q)
        self.call1 = BlackScholesCall(S=S, K=K2, T=T, r=r, sigma=sigma, q=q)
        self.call2 = BlackScholesCall(S=S, K=K3, T=T, r=r, sigma=sigma, q=q)

    def _calc_attr(self, attribute_name: str) -> float:
        """
        Combines attributes from two put and two call options into a long iron butterfly. \n
        All greeks and price are combined in the same way.

        :param attribute_name: String name of option attribute
        pointing to a method that can be called on
        BlackScholesCall and BlackScholesPut.

        :return: Combined value according to long iron butterfly.
        """
        put_attr1 = getattr(self.put1, attribute_name)
        put_attr2 = getattr(self.put2, attribute_name)
        call_attr1 = getattr(self.call1, attribute_name)
        call_attr2 = getattr(self.call2, attribute_name)
        return -put_attr1() + put_attr2() + call_attr1() - call_attr2()

Short

Bases: BlackScholesStructureBase

Create short iron butterfly option structure.

  • Short iron butterfly -> Put(K1) - Put(K2) - Call(K3) + Call(K4)

:param S: Price of underlying asset

:param K1: Strike price for 1st option

:param K2: Strike price for 2nd and 3rd option

:param K3: Strike price for 4th option

It must hold that K1 < K2 < K3.

Additionally, it must hold that K3 - K2 = K2 - K1 (equidistant strike prices)

:param T: Time till expiration in years (1/12 indicates 1 month)

:param r: Risk-free interest rate (0.05 indicates 5%)

:param sigma: Volatility (standard deviation) of stock (0.15 indicates 15%)

:param q: Annual dividend yield (0.05 indicates 5% yield)

Source code in blackscholes/iron_butterfly.py
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
class BlackScholesIronButterflyShort(BlackScholesStructureBase):
    """
    Create short iron butterfly option structure. \n
    - Short iron butterfly -> Put(K1) - Put(K2) - Call(K3) + Call(K4)

    :param S: Price of underlying asset \n
    :param K1: Strike price for 1st option \n
    :param K2: Strike price for 2nd and 3rd option \n
    :param K3: Strike price for 4th option \n
    It must hold that K1 < K2 < K3. \n
    Additionally, it must hold that K3 - K2 = K2 - K1 (equidistant strike prices) \n
    :param T: Time till expiration in years (1/12 indicates 1 month) \n
    :param r: Risk-free interest rate (0.05 indicates 5%) \n
    :param sigma: Volatility (standard deviation) of stock (0.15 indicates 15%) \n
    :param q: Annual dividend yield (0.05 indicates 5% yield)
    """

    def __init__(
        self,
        S: float,
        K1: float,
        K2: float,
        K3: float,
        T: float,
        r: float,
        sigma: float,
        q: float = 0.0,
    ):
        assert (
            K1 < K2 < K3
        ), f"""It must hold that K1 < K2 < K3.
        Got {K1}, {K2}, {K3}.
        """
        assert (
            K3 - K2 == K2 - K1
        ), f"""All strike prices must be equidistant, so K4 - K3 = K3 - K2 = K2 - K1.
        Got {K3}-{K2} != {K2}-{K1}.
        """
        super().__init__()
        self.put1 = BlackScholesPut(S=S, K=K1, T=T, r=r, sigma=sigma, q=q)
        self.put2 = BlackScholesPut(S=S, K=K2, T=T, r=r, sigma=sigma, q=q)
        self.call1 = BlackScholesCall(S=S, K=K2, T=T, r=r, sigma=sigma, q=q)
        self.call2 = BlackScholesCall(S=S, K=K3, T=T, r=r, sigma=sigma, q=q)

    def _calc_attr(self, attribute_name: str) -> float:
        """
        Combines attributes from two put and two call options into a short iron butterfly. \n
        All greeks and price are combined in the same way.

        :param attribute_name: String name of option attribute
        pointing to a method that can be called on
        BlackScholesCall and BlackScholesPut.

        :return: Combined value according to short iron butterfly.
        """
        put_attr1 = getattr(self.put1, attribute_name)
        put_attr2 = getattr(self.put2, attribute_name)
        call_attr1 = getattr(self.call1, attribute_name)
        call_attr2 = getattr(self.call2, attribute_name)
        return put_attr1() - put_attr2() - call_attr1() + call_attr2()

Mixins

Standard Normal Distribution

Fast PDF and CDF calculations for standard normal distribution.

Source code in blackscholes/base.py
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
class StandardNormalMixin:
    """
    Fast PDF and CDF calculations for standard normal distribution.
    """

    @staticmethod
    def _pdf(x: float) -> float:
        """PDF of standard normal distribution."""
        return exp(-(x**2) / 2.0) / sqrt(2.0 * pi)

    @staticmethod
    def _cdf(x):
        """CDF of standard normal distribution."""
        return (1.0 + erf(x / sqrt(2.0))) / 2.0