Coverage for src/scrilla/analysis/models/geometric/probability.py: 78%
42 statements
« prev ^ index » next coverage.py v6.4.2, created at 2022-07-18 18:14 +0000
« prev ^ index » next coverage.py v6.4.2, created at 2022-07-18 18:14 +0000
1# This file is part of scrilla: https://github.com/chinchalinchin/scrilla.
3# scrilla is free software: you can redistribute it and/or modify
4# it under the terms of the GNU General Public License version 3
5# as published by the Free Software Foundation.
7# scrilla is distributed in the hope that it will be useful,
8# but WITHOUT ANY WARRANTY; without even the implied warranty of
9# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10# GNU General Public License for more details.
12# You should have received a copy of the GNU General Public License
13# along with scrilla. If not, see <https://www.gnu.org/licenses/>
14# or <https://github.com/chinchalinchin/scrilla/blob/develop/main/LICENSE>.
15"""
16This module contains probability functions unique to the Geometric Brownian Motion stochastic model. All functions assume an asset price process that follows GBM. In other words, the return distribution is lognormal. This is equivalent to the Black-Scholes model from finance.
18The calculations have no stance on whether the actual probability distribution or the risk-neutral probability distribution should be used. This is implicitly specified by the user when they provided a rate of return to functions in this module. If the user wishes to use a risk-neutral probability, simply provide the assumed risk-free rate. If the user wishes to use an actual probability, provide the estimate of the rate of the return for the asset.
19"""
20from scipy.stats import norm
21from math import sqrt, exp, log
22from scrilla import settings
23from scrilla.util.outputter import Logger
25logger = Logger('scrilla.analysis.models.geometric.statistics',
26 settings.LOG_LEVEL)
29def d1(S0: float, ST: float, vol: float, ret: float, expiry: float, div: float = 0) -> float:
30 """
31 Returns the value of *d1* defined by the Black Scholes model (Geometric Brownian Motion)
33 Parameters
34 ----------
35 1. **S0** : ``float`
36 Initial value of the asset.
37 2. **ST** : ``float``
38 Final value of the asset.
39 3. **vol**: ``float``
40 Annualized volatility of the asset price process.
41 4. **ret**: ``float``
42 Annualized return of the asset price process.
43 5. **expiry**: ``float``
44 Time horizon in years, i.e. the time delta between `ST` and `S0` measured in years.
45 6. **div**: ``float``
46 *Optional*. Annualized dividend yield. Defaults to 0.
48 Returns
49 -------
50 ``float`` : Black-Scholes *d1*
51 """
52 numerator = log(S0/ST) + (ret - div + 0.5 * (vol ** 2))*expiry
53 denominator = vol * sqrt(expiry)
54 return (numerator/denominator)
57def d2(S0: float, ST: float, vol: float, ret: float, expiry: float, div: float = 0) -> float:
58 """
59 Returns the value of *d2* defined by the Black Scholes model (Geometric Brownian Motion)
61 Parameters
62 ----------
63 1. **S0** : ``float``
64 Initial value of the asset.
65 2. **ST** : ``float``
66 Final value of the asset.
67 3. **vol**: ``float``
68 Annualized volatility of the asset price process.
69 4. **ret**: ``float``
70 Annualized return of the asset price process.
71 5. **expiry**: ``float``
72 Time horizon in years, i.e. the time delta between `ST` and `S0` measured in years.
73 6. **div**: ``float``
74 *Optional*. Annualized dividend yield. Defaults to 0.
76 Returns
77 -------
78 ``float`` : Black-Scholes *d2*
79 """
80 thisD1 = d1(S0=S0, ST=ST, vol=vol, ret=ret, expiry=expiry, div=div)
81 adjust = vol * sqrt(expiry)
82 return (thisD1 - adjust)
85def prob_d1(S0: float, ST: float, vol: float, ret: float, expiry: float, div: float = 0, neg: bool = False) -> float:
86 """
87 Returns the probability of *d1* defined by the Black Scholes model (Geometric Brownian Motion)
89 Parameters
90 ----------
91 1. **S0** : ``float``
92 Initial value of the asset.
93 2. **ST** : ``float`
94 Final value of the asset.
95 3. **vol**: ``float``
96 Annualized volatility of the asset price process.
97 4. **ret**: ``float``
98 Annualized return of the asset price process.
99 5. **expiry**: ``float``
100 Time horizon in years, i.e. the time delta between `ST` and `S0` measured in years.
101 6. **div**: ``float``
102 *Optional*. Annualized dividend yield. Defaults to 0.
103 7. **neg**: ``bool``
104 *Optional*. Calculates the probability of *-d1*. Defaults to `False`.
106 Returns
107 -------
108 ``float`` : cumulative probability of *d1*
109 """
110 if vol == 0: 110 ↛ 111line 110 didn't jump to line 111, because the condition on line 110 was never true
111 pass
112 thisD1 = d1(S0=S0, ST=ST, vol=vol, ret=ret, expiry=expiry, div=div)
113 if neg:
114 thisD1 = -thisD1
115 return norm.cdf(thisD1)
118def prob_d2(S0: float, ST: float, vol: float, ret: float, expiry: float, div: float = 0, neg: bool = False):
119 """
120 Returns the probability of *d2* defined by the Black Scholes model (Geometric Brownian Motion)
122 Parameters
123 ----------
124 1. **S0** : ``float``
125 Initial value of the asset.
126 2. **ST** : ``float`
127 Final value of the asset.
128 3. **vol**: ``float``
129 Annualized volatility of the asset price process.
130 4. **ret**: ``float``
131 Annualized return of the asset price process.
132 5. **expiry**: ``float``
133 Time horizon in years, i.e. the time delta between `ST` and `S0`.
134 6. **div**: ``float``
135 *Optional*. Annualized dividend yield. Defaults to 0.
136 7. **neg**: ``bool``
137 *Optional*. Calculates the probability of *-d2*. Defaults to `False`.
139 Returns
140 -------
141 ``float`` : cumulative probability of *d2*
142 """
143 # if no uncertainty
144 if vol == 0: 144 ↛ 146line 144 didn't jump to line 146, because the condition on line 144 was never true
145 # if the future value of initial price is greater than the strike
146 if S0*exp((ret-div)*expiry) > ST:
147 # probability(S>St)=1
148 return 1
149 # probability(S>St)=0
150 return 0
152 thisD2 = d2(S0=S0, ST=ST, vol=vol, ret=ret, expiry=expiry, div=div)
153 if neg: 153 ↛ 155line 153 didn't jump to line 155, because the condition on line 153 was never false
154 thisD2 = -thisD2
155 return norm.cdf(thisD2)
158def percentile(S0: float, vol: float, ret: float, expiry: float, prob: float, div: float = 0) -> float:
159 """
160 Returns the final value of the asset price over the time horizon `expiry` that corresponds the `percentile` of the price's distribution. The asset price process is assumed to follow Geometric Brownian Motion, i.e. the return distribution is lognormal.
162 Parameters
163 ----------
164 1. **S0** : ``float``
165 Initial value of the asset.
166 2. **vol**: ``float``
167 Annualized volatility of the asset price process.
168 3. **ret**: ``float``
169 Annualized return of the asset price process.
170 4. **expiry**: ``float``
171 Time horizon in years, i.e. the time delta between `ST` and `S0` measured in years.
172 5. **prob**: ``float``
173 Percentile of the distribution to be returned, i.e. if S is the price process and \\(S_t\\) is the percentile,
175 $$ Pr(S<S_t)=prob $$
177 6. **div**: ``float``
178 *Optional*. Annualized dividend yield. Defaults to 0.
180 Returns
181 -------
182 ``float`` : percentile of lognormal distribution
184 .. notes::
185 * Percentiles are preserved under log transformations, so the asset percentile is equal to the exponentiated return percentile. See Wiki article for more information: https://en.wikipedia.org/wiki/Log-normal_distribution#Mode,_median,_quantiles
186 """
187 inv_norm = norm.ppf(prob)
188 exponent = (ret - div - 0.5*(vol**2))*expiry + vol*sqrt(expiry)*inv_norm
189 return (S0*exp(exponent))
192def conditional_expected_value(S0: float, vol: float, ret: float, expiry: float, conditional_value: float, greater: bool = False, div: float = 0) -> float:
193 """
194 Calculates the conditional expected value of an equity, assuming the price process follows Geometric Brownian Motion, i.e. the price distribution is lognormal.
196 Note: Returns either
197 >>> if greater:
198 >>> E( St | St > condtional_value)
199 >>> if not greater:
200 >>> E( St | St < conditional_value)
202 Parameters
203 ----------
204 1. **S0** : ``float``
205 Initial equity price.
206 2. **vol** : ``float``
207 Annualized volatility.
208 3. ***ret**: ``float``
209 Annualized return.
210 4. **expiry** : ``float``
211 Time in years until the condition is evaluated.
212 5. **conditional_value**: ``float``
213 The value of the equity conditioned on at time ``expiry``.
214 6. **greater** : ``boolean``
215 *Optional*. Defaults to `False`. Determines the direction of the inequality for the condition attached to the expectation. See function description for more information.
216 7. **div**: ``float``
217 *Optional*. Defaults to `0`. Annualized dividend yield.
218 """
219 forward_value = S0*exp((ret - div)*expiry)
220 if greater: 220 ↛ 221line 220 didn't jump to line 221, because the condition on line 220 was never true
221 this_prob_d1 = prob_d1(S0=S0, ST=conditional_value,
222 vol=vol, ret=ret, expiry=expiry, div=div)
223 this_prob_d2 = prob_d2(S0=S0, ST=conditional_value,
224 vol=vol, ret=ret, expiry=expiry, div=div)
225 else:
226 this_prob_d1 = prob_d1(S0=S0, ST=conditional_value,
227 vol=vol, ret=ret, expiry=expiry, div=div, neg=True)
228 this_prob_d2 = prob_d2(S0=S0, ST=conditional_value,
229 vol=vol, ret=ret, expiry=expiry, div=div, neg=True)
231 return (forward_value*this_prob_d1/this_prob_d2)