Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit bdc2831

Browse filesBrowse files
jstacHumphreyYangmmcky
authored
Added Option Pricing Exercises (#236)
* Added Option Pricing Exercises * fix default values * update hint admonitions * misc * Update lectures/parallelization.md * Update lectures/scipy.md * Update lectures/scipy.md * Update lectures/scipy.md * Update lectures/parallelization.md * Update lectures/parallelization.md * Update lectures/scipy.md Fixed Typo Co-authored-by: Humphrey Yang <u6474961@anu.edu.au> Co-authored-by: mmcky <mmcky@users.noreply.github.com>
1 parent a545bda commit bdc2831
Copy full SHA for bdc2831

File tree

Expand file treeCollapse file tree

2 files changed

+249
-1
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

2 files changed

+249
-1
lines changed
Open diff view settings
Collapse file

‎lectures/parallelization.md‎

Copy file name to clipboardExpand all lines: lectures/parallelization.md
+116Lines changed: 116 additions & 0 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -486,3 +486,119 @@ on the number of CPUs on your machine.)
486486

487487
```{solution-end}
488488
```
489+
490+
491+
```{exercise}
492+
:label: parallel_ex2
493+
494+
In {doc}`our lecture on SciPy<scipy>`, we discussed pricing a call option in a
495+
setting where the underlying stock price had a simple and well-known
496+
distribution.
497+
498+
Here we discuss a more realistic setting.
499+
500+
We recall that the price of the option obeys
501+
502+
$$
503+
P = \beta^n \mathbb E \max\{ S_n - K, 0 \}
504+
$$
505+
506+
where
507+
508+
1. $\beta$ is a discount factor,
509+
2. $n$ is the expiry date,
510+
2. $K$ is the strike price and
511+
3. $\{S_t\}$ is the price of the underlying asset at each time $t$.
512+
513+
Suppose that `n, β, K = 20, 0.99, 100`.
514+
515+
Assume that the stock price obeys
516+
517+
$$
518+
\ln \frac{S_{t+1}}{S_t} = \mu + \sigma_t \xi_{t+1}
519+
$$
520+
521+
where
522+
523+
$$
524+
\sigma_t = \exp(h_t),
525+
\quad
526+
h_{t+1} = \rho h_t + \nu \eta_{t+1}
527+
$$
528+
529+
Here $\{\xi_t\}$ and $\{\eta_t\}$ are IID and standard normal.
530+
531+
(This is a **stochastic volatility** model, where the volatility $\sigma_t$
532+
varies over time.)
533+
534+
Use the defaults `μ, ρ, ν, S0, h0 = 0.0001, 0.1, 0.001, 10, 0`.
535+
536+
(Here `S0` is $S_0$ and `h0` is $h_0$.)
537+
538+
By generating $M$ paths $s_0, \ldots, s_n$, compute the Monte Carlo estimate
539+
540+
$$
541+
\hat P_M
542+
:= \beta^n \mathbb E \max\{ S_n - K, 0 \}
543+
\approx
544+
\frac{1}{M} \sum_{m=1}^M \max \{S_n^m - K, 0 \}
545+
$$
546+
547+
548+
of the price, applying Numba and parallelization.
549+
550+
```
551+
552+
553+
```{solution-start} parallel_ex2
554+
:class: dropdown
555+
```
556+
557+
558+
With $s_t := \ln S_t$, the price dynamics become
559+
560+
$$
561+
s_{t+1} = s_t + \mu + \exp(h_t) \xi_{t+1}
562+
$$
563+
564+
Using this fact, the solution can be written as follows.
565+
566+
567+
```{code-cell} ipython3
568+
from numpy.random import randn
569+
M = 10_000_000
570+
571+
n, β, K = 20, 0.99, 100
572+
μ, ρ, ν, S0, h0 = 0.0001, 0.1, 0.001, 10, 0
573+
574+
@njit(parallel=True)
575+
def compute_call_price_parallel(β=β,
576+
μ=μ,
577+
S0=S0,
578+
h0=h0,
579+
K=K,
580+
n=n,
581+
ρ=ρ,
582+
ν=ν,
583+
M=M):
584+
current_sum = 0.0
585+
# For each sample path
586+
for m in prange(M):
587+
s = np.log(S0)
588+
h = h0
589+
# Simulate forward in time
590+
for t in range(n):
591+
s = s + μ + np.exp(h) * randn()
592+
h = ρ * h + ν * randn()
593+
# And add the value max{S_n - K, 0} to current_sum
594+
current_sum += np.maximum(np.exp(s) - K, 0)
595+
596+
return β**n * current_sum / M
597+
```
598+
599+
Try swapping between `parallel=True` and `parallel=False` and noting the run time.
600+
601+
If you are on a machine with many CPUs, the difference should be significant.
602+
603+
```{solution-end}
604+
```
Collapse file

‎lectures/scipy.md‎

Copy file name to clipboardExpand all lines: lectures/scipy.md
+133-1Lines changed: 133 additions & 1 deletion
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -440,12 +440,144 @@ We leave you to investigate the [set of available routines](http://docs.scipy.or
440440

441441
## Exercises
442442

443+
The first few exercises concern pricing a European call option under the
444+
assumption of risk neutrality. The price satisfies
445+
446+
$$
447+
P = \beta^n \mathbb E \max\{ S_n - K, 0 \}
448+
$$
449+
450+
where
451+
452+
1. $\beta$ is a discount factor,
453+
2. $n$ is the expiry date,
454+
2. $K$ is the strike price and
455+
3. $\{S_t\}$ is the price of the underlying asset at each time $t$.
456+
457+
For example, if the call option is to buy stock in Amazon at strike price $K$, the owner has the right (but not the obligation) to buy 1 share in Amazon at price $K$ after $n$ days.
458+
459+
The payoff is therefore $\max\{S_n - K, 0\}$
460+
461+
The price is the expectation of the payoff, discounted to current value.
462+
463+
464+
```{exercise-start}
465+
:label: sp_ex01
466+
```
467+
468+
Suppose that $S_n$ has the [log-normal](https://en.wikipedia.org/wiki/Log-normal_distribution) distribution with parameters $\mu$ and $\sigma$. Let $f$ denote the density of this distribution. Then
469+
470+
$$
471+
P = \beta^n \int_0^\infty \max\{x - K, 0\} f(x) dx
472+
$$
473+
474+
Plot the function
475+
476+
$$
477+
g(x) = \beta^n \max\{x - K, 0\} f(x)
478+
$$
479+
480+
over the interval $[0, 400]$ when `μ, σ, β, n, K = 4, 0.25, 0.99, 10, 40`.
481+
482+
```{hint}
483+
:class: dropdown
484+
485+
From `scipy.stats` you can import `lognorm` and then use `lognorm(x, σ, scale=np.exp(μ)` to get the density $f$.
486+
```
487+
488+
```{exercise-end}
489+
```
490+
491+
```{solution-start} sp_ex01
492+
:class: dropdown
493+
```
494+
495+
Here's one possible solution
496+
497+
```{code-cell} ipython3
498+
from scipy.integrate import quad
499+
from scipy.stats import lognorm
500+
501+
μ, σ, β, n, K = 4, 0.25, 0.99, 10, 40
502+
503+
def g(x):
504+
return β**n * np.maximum(x - K, 0) * lognorm.pdf(x, σ, scale=np.exp(μ))
505+
506+
x_grid = np.linspace(0, 400, 1000)
507+
y_grid = g(x_grid)
508+
509+
fig, ax = plt.subplots()
510+
ax.plot(x_grid, y_grid, label="$g$")
511+
ax.legend()
512+
plt.show()
513+
```
514+
515+
```{solution-end}
516+
```
517+
518+
```{exercise}
519+
:label: sp_ex02
520+
521+
In order to get the option price, compute the integral of this function numerically using `quad` from `scipy.optimize`.
522+
523+
```
524+
525+
```{solution-start} sp_ex02
526+
:class: dropdown
527+
```
528+
529+
```{code-cell} ipython3
530+
P, error = quad(g, 0, 1_000)
531+
print(f"The numerical integration based option price is {P:.3f}")
532+
```
533+
534+
```{solution-end}
535+
```
536+
537+
```{exercise}
538+
:label: sp_ex03
539+
540+
Try to get a similar result using Monte Carlo to compute the expectation term in the option price, rather than `quad`.
541+
542+
In particular, use the fact that if $S_n^1, \ldots, S_n^M$ are independent
543+
draws from the lognormal distribution specified above, then, by the law of
544+
large numbers,
545+
546+
$$ \mathbb E \max\{ S_n - K, 0 \}
547+
\approx
548+
\frac{1}{M} \sum_{m=1}^M \max \{S_n^m - K, 0 \}
549+
$$
550+
551+
Set `M = 10_000_000`
552+
553+
```
554+
555+
```{solution-start} sp_ex03
556+
:class: dropdown
557+
```
558+
559+
Here is one solution:
560+
561+
```{code-cell} ipython3
562+
M = 10_000_000
563+
S = np.exp(μ + σ * np.random.randn(M))
564+
return_draws = np.maximum(S - K, 0)
565+
P = β**n * np.mean(return_draws)
566+
print(f"The Monte Carlo option price is {P:3f}")
567+
```
568+
569+
570+
```{solution-end}
571+
```
572+
573+
574+
443575
```{exercise}
444576
:label: sp_ex1
445577
446578
In {ref}`this lecture <functions>`, we discussed the concept of {ref}`recursive function calls <recursive_functions>`.
447579
448-
Try to write a recursive implementation of homemade bisection function {ref}`described above <bisect_func>`.
580+
Try to write a recursive implementation of the homemade bisection function {ref}`described above <bisect_func>`.
449581
450582
Test it on the function {eq}`root_f`.
451583
```

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.