Skip to content

Commit 1ef8a7a

Browse files
committed
Added docstrings
1 parent f2a7ce9 commit 1ef8a7a

File tree

5 files changed

+225
-81
lines changed

5 files changed

+225
-81
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
/Manifest.toml
1+
**/Manifest.toml

src/pricing_methods/black_scholes.jl

Lines changed: 38 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,49 @@
1+
# Black-Scholes pricing function for European vanilla options
12

2-
"""Computes the price of a vanilla European call option using the Black-Scholes model.
3+
"""
4+
Computes the price of a vanilla European call or put option using the Black-Scholes model.
35
46
# Arguments
5-
- `pricer::Pricer{VanillaCall, BlackScholesInputs, BlackScholesMethod}`:
6-
A `Pricer` configured for Black-Scholes pricing of a vanilla European call.
7+
- `payoff::VanillaOption{European}`:
8+
A European-style vanilla option, either a call or put.
9+
- `marketInputs::BlackScholesInputs`:
10+
The market inputs required for Black-Scholes pricing, including forward price, risk-free rate, and volatility.
11+
- `::BlackScholesMethod`:
12+
A placeholder argument to specify the Black-Scholes pricing method.
713
814
# Returns
9-
- The computed Black-Scholes price of the option.
15+
- The discounted expected price of the option under the Black-Scholes model.
16+
17+
# Formula
18+
The Black-Scholes price is computed using:
1019
11-
The Black-Scholes formula used is:
1220
```
13-
d1 = (log(S / K) + (r + 0.5 * σ^2) * T) / (σ * sqrt(T))
21+
d1 = (log(F / K) + 0.5 * σ^2 * T) / (σ * sqrt(T))
1422
d2 = d1 - σ * sqrt(T)
15-
price = S * Φ(d1) - K * exp(-r * T) * Φ(d2)
23+
price = exp(-r * T) * cp * (F * Φ(cp * d1) - K * Φ(cp * d2))
1624
```
17-
where `Φ` is the CDF of the standard normal distribution.
25+
26+
where:
27+
- `F` is the forward price of the underlying,
28+
- `K` is the strike price,
29+
- `σ` is the volatility,
30+
- `r` is the risk-free rate,
31+
- `T` is the time to expiry in years,
32+
- `cp` is +1 for calls and -1 for puts,
33+
- `Φ(x)` is the cumulative distribution function (CDF) of the standard normal distribution.
34+
35+
# Notes
36+
- The time to expiry `T` is computed as the difference between the option's expiry date and the reference date, assuming a 365-day year.
37+
- The function supports both call and put options through the `cp` factor, ensuring a unified formula.
1838
"""
1939
function compute_price(payoff::VanillaOption{European}, marketInputs::BlackScholesInputs, ::BlackScholesMethod)
20-
F = marketInputs.forward
21-
K = payoff.strike
22-
r = marketInputs.rate
23-
σ = marketInputs.sigma
24-
cp = payoff.call_put()
25-
T = Dates.value.(payoff.expiry .- marketInputs.referenceDate) ./ 365 # we might want to specify daycount conventions to ensure consistency
26-
d1 = (log(F / K) + 0.5 * σ^2 * T) /* sqrt(T))
27-
d2 = d1 - σ * sqrt(T)
28-
return exp(-r*T) * cp * (F * cdf(Normal(), cp * d1) - K * cdf(Normal(), cp * d2))
29-
end
40+
F = marketInputs.forward
41+
K = payoff.strike
42+
r = marketInputs.rate
43+
σ = marketInputs.sigma
44+
cp = payoff.call_put()
45+
T = Dates.value.(payoff.expiry .- marketInputs.referenceDate) ./ 365 # Assuming 365-day convention
46+
d1 = (log(F / K) + 0.5 * σ^2 * T) /* sqrt(T))
47+
d2 = d1 - σ * sqrt(T)
48+
return exp(-r*T) * cp * (F * cdf(Normal(), cp * d1) - K * cdf(Normal(), cp * d2))
49+
end
Lines changed: 112 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,128 @@
1-
"""The Cox-Ross-Rubinstein binomial tree pricing method.
1+
# Cox-Ross-Rubinstein Binomial Tree Pricing Implementation
22

3-
This struct represents the Cox-Ross-Rubinstein binomial pricing model for option pricing.
3+
"""
4+
The Cox-Ross-Rubinstein binomial tree pricing method.
5+
6+
This struct represents the Cox-Ross-Rubinstein (CRR) binomial pricing model for option pricing.
7+
8+
# Fields
9+
- `steps`: The number of time steps in the binomial tree.
10+
11+
# Notes
12+
- This implementation supports options written on either the **forward price** or the **spot price**.
13+
- When pricing an option on the forward price, discounting is already embedded in the forward.
14+
- When pricing an option on the spot price, discounting must be explicitly applied at each step.
15+
- The up probability is defined as:
16+
17+
```
18+
p = 1 / (1 + u)
19+
```
20+
where:
21+
- `u = exp(σ√ΔT)` is the up-move factor,
22+
- `ΔT` is the time step duration in years.
423
"""
524
struct CoxRossRubinsteinMethod <: AbstractPricingMethod
6-
steps
25+
steps::Int
726
end
827

9-
function binomial_tree_value(step, discounted_continuation, underlying_at_i, payoff, ::European)
10-
return discounted_continuation
28+
"""
29+
Returns the value at a given node in the binomial tree for a European option.
30+
31+
# Arguments
32+
- `discounted_continuation`: Discounted expected future values from the next step.
33+
- `::European`: Marker type for European exercise style.
34+
35+
# Returns
36+
- The continuation value, as European options do not allow early exercise.
37+
"""
38+
function binomial_tree_value(_, discounted_continuation, _, _, ::European)
39+
return discounted_continuation
1140
end
1241

42+
"""
43+
Returns the value at a given node in the binomial tree for an American option.
44+
45+
# Arguments
46+
- `step`: Current time step in the binomial tree.
47+
- `discounted_continuation`: Discounted expected future values from the next step.
48+
- `underlying_at_i`: Function to compute the underlying price at a given step.
49+
- `payoff`: Payoff function of the option.
50+
- `::American`: Marker type for American exercise style.
51+
52+
# Returns
53+
- The maximum between the continuation value and the intrinsic value of the option (early exercise is considered).
54+
"""
1355
function binomial_tree_value(step, discounted_continuation, underlying_at_i, payoff, ::American)
14-
return max.(discounted_continuation, payoff(underlying_at_i(step)))
56+
return max.(discounted_continuation, payoff(underlying_at_i(step)))
1557
end
1658

59+
"""
60+
Computes the underlying asset price at a given step when pricing an option on the **spot price**.
61+
62+
# Arguments
63+
- `time_step`: Current time step in the binomial tree.
64+
- `forward`: Forward price of the underlying asset.
65+
- `rate`: Risk-free rate.
66+
- `delta_time`: Time step size in years.
67+
- `::Spot`: Marker type indicating the option is written on the spot price.
68+
69+
# Returns
70+
- The estimated spot price, derived by discounting the forward price.
71+
"""
1772
function binomial_tree_underlying(time_step, forward, rate, delta_time, ::Spot)
18-
return exp(-rate*time_step*delta_time) * forward
73+
return exp(-rate * time_step * delta_time) * forward
1974
end
2075

76+
"""
77+
Computes the underlying asset price at a given step when pricing an option on the **forward price**.
78+
79+
# Arguments
80+
- `forward`: Forward price of the underlying asset.
81+
- `::Forward`: Marker type indicating the option is written on the forward price.
82+
83+
# Returns
84+
- The forward price (unchanged, as forward prices already embed discounting).
85+
"""
2186
function binomial_tree_underlying(_, forward, _, _, ::Forward)
22-
return forward
87+
return forward
2388
end
2489

25-
function compute_price(payoff::P, market_inputs::BlackScholesInputs, method::CoxRossRubinsteinMethod) where P <: AbstractPayoff
26-
ΔT = Dates.value.(payoff.expiry .- market_inputs.referenceDate) ./ 365 / method.steps # we might want to specify daycount conventions to ensure consistency
27-
up_step = exp(market_inputs.sigma * sqrt(ΔT))
28-
forward_at_i(i) = market_inputs.forward * up_step .^ (-i:2:i)
29-
underlying_at_i(i) = binomial_tree_underlying(i, forward_at_i(i), market_inputs.rate, ΔT, payoff.underlying)
30-
up_probability = 1 / (1 + up_step)
31-
value = payoff(forward_at_i(method.steps))
32-
33-
for step in (method.steps-1):-1:0
34-
continuation = up_probability * value[2:end] + (1 - up_probability) * value[1:end-1]
35-
df = exp(-market_inputs.rate * ΔT)
36-
value = binomial_tree_value(step, df * continuation, underlying_at_i, payoff, payoff.exercise_style)
37-
end
38-
39-
return value[1]
40-
end
90+
"""
91+
Computes the price of a vanilla option using the Cox-Ross-Rubinstein binomial tree model.
92+
93+
# Arguments
94+
- `payoff`: The option payoff function, which determines intrinsic value.
95+
- `market_inputs`: Market data including forward price, risk-free rate, and volatility.
96+
- `method`: The CRR pricing method with a defined number of steps.
97+
98+
# Returns
99+
- The computed option price using backward induction.
100+
101+
# Notes
102+
- This implementation supports **options on either forward prices or spot prices**.
103+
- If the option is written on a forward price, discounting is embedded.
104+
- If the option is written on a spot price, discounting is applied explicitly.
105+
- The up-move factor is computed as `u = exp(σ√ΔT)`, and the up probability is given by `p = 1 / (1 + u)`.
106+
"""
107+
function compute_price(payoff, market_inputs, method::CoxRossRubinsteinMethod)
108+
steps = method.steps
109+
ΔT = Dates.value.(payoff.expiry - market_inputs.referenceDate) / 365 / steps # Assuming ACT/365 day count
110+
u = exp(market_inputs.sigma * sqrt(ΔT)) # Up-move factor
111+
forward_at_i(i) = market_inputs.forward * u .^ (-i:2:i)
112+
underlying_at_i(i) = binomial_tree_underlying(i, forward_at_i(i), market_inputs.rate, ΔT, payoff.underlying)
113+
114+
# Up probability in forward measure
115+
p = 1 / (1 + u)
116+
117+
# Initialize terminal payoffs
118+
value = payoff.(forward_at_i(steps))
119+
120+
# Backward induction
121+
for step in (steps-1):-1:0
122+
continuation = p * value[2:end] + (1 - p) * value[1:end-1]
123+
df = exp(-market_inputs.rate * ΔT) # Discounting
124+
value = binomial_tree_value(step, df * continuation, underlying_at_i, payoff, payoff.exercise_style)
125+
end
126+
127+
return value[1]
128+
end
Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,34 @@
1+
# Exported Types and Functions
12
export AbstractPricingMethod, BlackScholesMethod, Pricer, compute_price, CoxRossRubinsteinMethod
23

3-
"""An abstract type representing a pricing method."""
4+
"""
5+
An abstract type representing a pricing method.
6+
7+
All pricing methods, such as Black-Scholes or binomial trees, should inherit from this type.
8+
"""
49
abstract type AbstractPricingMethod end
510

6-
"""The Black-Scholes pricing method.
11+
"""
12+
The Black-Scholes pricing method.
713
8-
This struct represents the Black-Scholes pricing model for option pricing.
14+
This struct represents the Black-Scholes pricing model for option pricing, which assumes a lognormal distribution for the underlying asset and continuous hedging.
915
"""
1016
struct BlackScholesMethod <: AbstractPricingMethod end
1117

12-
"""A pricer that calculates the price of a derivative using a given payoff, market data, and a pricing model.
18+
"""
19+
A pricer that calculates the price of a derivative using a given payoff, market data, and a pricing model.
1320
1421
# Type Parameters
15-
- `P <: AbstractPayoff`: The type of payoff being priced.
16-
- `M <: AbstractMarketInputs`: The type of market data inputs required for pricing.
17-
- `S <: AbstractPricingMethod`: The pricing method used.
22+
- `P`: The type of payoff being priced (must be a subtype of `AbstractPayoff`).
23+
- `M`: The type of market data inputs required for pricing (must be a subtype of `AbstractMarketInputs`).
24+
- `S`: The pricing method used (must be a subtype of `AbstractPricingMethod`).
1825
1926
# Fields
20-
- `marketInputs::M`: The market data inputs used for pricing.
21-
- `payoff::P`: The derivative payoff.
22-
- `pricingMethod::S`: The pricing model used for valuation.
27+
- `payoff`: The derivative payoff.
28+
- `marketInputs`: The market data inputs used for pricing.
29+
- `pricingMethod`: The pricing model used for valuation.
2330
24-
A `Pricer` is a callable struct that computes the price of the derivative using the specified pricing method.
31+
A `Pricer` is a callable struct that computes the price of the derivative using the specified pricing method when invoked.
2532
"""
2633
struct Pricer{P <: AbstractPayoff, M <: AbstractMarketInputs, S <: AbstractPricingMethod}
2734
payoff::P
@@ -30,16 +37,16 @@ struct Pricer{P <: AbstractPayoff, M <: AbstractMarketInputs, S <: AbstractPrici
3037
end
3138

3239
"""
33-
Computes the price based on a Pricer input object.
40+
Computes the price of a derivative using a `Pricer` object.
3441
35-
# Arguments
36-
- `pricer::Pricer{A, B, C}`:
37-
A `Pricer`, specifying a payoff, a market inputs and a method.
42+
# Arguments
43+
- `pricer`: A `Pricer` containing the payoff, market inputs, and pricing method.
3844
3945
# Returns
40-
- The computed price of the derivative.
46+
- The computed price of the derivative based on the specified pricing model.
4147
48+
This function allows a `Pricer` instance to be called directly as a function, forwarding the computation to `compute_price`.
4249
"""
4350
function (pricer::Pricer{A,B,C})() where {A<:AbstractPayoff,B<:AbstractMarketInputs,C<:AbstractPricingMethod}
4451
return compute_price(pricer.payoff, pricer.marketInputs, pricer.pricingMethod)
45-
end
52+
end

0 commit comments

Comments
 (0)