Module: OptionLab::BlackScholes
- Defined in:
- lib/option_lab/black_scholes.rb
Class Method Summary collapse
-
.get_bs_info(s, x, r, vol, years_to_maturity, y = 0.0) ⇒ Models::BlackScholesInfo
Get all Black-Scholes info.
-
.get_d1(s0, x, r, vol, years_to_maturity, y = 0.0) ⇒ Float, Numo::DFloat
Get d1 parameter for Black-Scholes formula.
-
.get_d2(s0, x, r, vol, years_to_maturity, y = 0.0) ⇒ Float, Numo::DFloat
Get d2 parameter for Black-Scholes formula.
-
.get_delta(option_type, d1, years_to_maturity, y = 0.0) ⇒ Float, Numo::DFloat
Get option delta.
-
.get_gamma(s0, vol, years_to_maturity, d1, y = 0.0) ⇒ Float, Numo::DFloat
Get option gamma.
-
.get_implied_vol(option_type, oprice, s0, x, r, years_to_maturity, y = 0.0) ⇒ Float
Get implied volatility.
-
.get_itm_probability(option_type, d2, years_to_maturity, y = 0.0) ⇒ Float, Numo::DFloat
Get in-the-money probability.
-
.get_option_price(option_type, s0, x, r, years_to_maturity, d1, d2, y = 0.0) ⇒ Float, Numo::DFloat
Get option price using Black-Scholes formula.
-
.get_rho(option_type, x, r, years_to_maturity, d2) ⇒ Float, Numo::DFloat
Get option rho.
-
.get_theta(option_type, s0, x, r, vol, years_to_maturity, d1, d2, y = 0.0) ⇒ Float, Numo::DFloat
Get option theta.
-
.get_vega(s0, years_to_maturity, d1, y = 0.0) ⇒ Float, Numo::DFloat
Get option vega.
Class Method Details
.get_bs_info(s, x, r, vol, years_to_maturity, y = 0.0) ⇒ Models::BlackScholesInfo
Get all Black-Scholes info
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 |
# File 'lib/option_lab/black_scholes.rb', line 226 def get_bs_info(s, x, r, vol, years_to_maturity, y = 0.0) d1 = get_d1(s, x, r, vol, years_to_maturity, y) d2 = get_d2(s, x, r, vol, years_to_maturity, y) call_price = get_option_price('call', s, x, r, years_to_maturity, d1, d2, y) put_price = get_option_price('put', s, x, r, years_to_maturity, d1, d2, y) call_delta = get_delta('call', d1, years_to_maturity, y) put_delta = get_delta('put', d1, years_to_maturity, y) call_theta = get_theta('call', s, x, r, vol, years_to_maturity, d1, d2, y) put_theta = get_theta('put', s, x, r, vol, years_to_maturity, d1, d2, y) gamma = get_gamma(s, vol, years_to_maturity, d1, y) vega = get_vega(s, years_to_maturity, d1, y) call_rho = get_rho('call', x, r, years_to_maturity, d2) put_rho = get_rho('put', x, r, years_to_maturity, d2) call_itm_prob = get_itm_probability('call', d2, years_to_maturity, y) put_itm_prob = get_itm_probability('put', d2, years_to_maturity, y) Models::BlackScholesInfo.new( call_price: call_price, put_price: put_price, call_delta: call_delta, put_delta: put_delta, call_theta: call_theta, put_theta: put_theta, gamma: gamma, vega: vega, call_rho: call_rho, put_rho: put_rho, call_itm_prob: call_itm_prob, put_itm_prob: put_itm_prob, ) end |
.get_d1(s0, x, r, vol, years_to_maturity, y = 0.0) ⇒ Float, Numo::DFloat
Get d1 parameter for Black-Scholes formula
20 21 22 23 24 25 26 27 |
# File 'lib/option_lab/black_scholes.rb', line 20 def get_d1(s0, x, r, vol, years_to_maturity, y = 0.0) # Handle edge cases return 0.0 if years_to_maturity <= 0.0 || vol <= 0.0 numerator = Math.log(s0 / x) + (r - y + 0.5 * vol * vol) * years_to_maturity denominator = vol * Math.sqrt(years_to_maturity) numerator / denominator end |
.get_d2(s0, x, r, vol, years_to_maturity, y = 0.0) ⇒ Float, Numo::DFloat
Get d2 parameter for Black-Scholes formula
37 38 39 40 41 42 43 |
# File 'lib/option_lab/black_scholes.rb', line 37 def get_d2(s0, x, r, vol, years_to_maturity, y = 0.0) # Handle edge cases return 0.0 if years_to_maturity <= 0.0 || vol <= 0.0 d1 = get_d1(s0, x, r, vol, years_to_maturity, y) d1 - vol * Math.sqrt(years_to_maturity) end |
.get_delta(option_type, d1, years_to_maturity, y = 0.0) ⇒ Float, Numo::DFloat
Get option delta
81 82 83 84 85 86 87 88 89 90 91 92 |
# File 'lib/option_lab/black_scholes.rb', line 81 def get_delta(option_type, d1, years_to_maturity, y = 0.0) yfac = Math.exp(-y * years_to_maturity) case option_type when 'call' yfac * Distribution::Normal.cdf(d1) when 'put' yfac * (Distribution::Normal.cdf(d1) - 1.0) else raise ArgumentError, "Option type must be either 'call' or 'put'!" end end |
.get_gamma(s0, vol, years_to_maturity, d1, y = 0.0) ⇒ Float, Numo::DFloat
Get option gamma
101 102 103 104 105 106 107 108 |
# File 'lib/option_lab/black_scholes.rb', line 101 def get_gamma(s0, vol, years_to_maturity, d1, y = 0.0) yfac = Math.exp(-y * years_to_maturity) # PDF of d1 cdf_d1_prime = Math.exp(-0.5 * d1 * d1) / Math.sqrt(2.0 * Math::PI) yfac * cdf_d1_prime / (s0 * vol * Math.sqrt(years_to_maturity)) end |
.get_implied_vol(option_type, oprice, s0, x, r, years_to_maturity, y = 0.0) ⇒ Float
Get implied volatility
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 |
# File 'lib/option_lab/black_scholes.rb', line 200 def get_implied_vol(option_type, oprice, s0, x, r, years_to_maturity, y = 0.0) # Start with volatilities from 0.001 to 1.0 in steps of 0.001 volatilities = (1..1000).map { |i| i * 0.001 } # Calculate option prices for each volatility prices = volatilities.map do |vol| d1 = get_d1(s0, x, r, vol, years_to_maturity, y) d2 = get_d2(s0, x, r, vol, years_to_maturity, y) get_option_price(option_type, s0, x, r, years_to_maturity, d1, d2, y) end # Calculate absolute differences from market price diffs = prices.map { |price| (price - oprice).abs } # Return volatility with minimal difference volatilities[diffs.index(diffs.min)] end |
.get_itm_probability(option_type, d2, years_to_maturity, y = 0.0) ⇒ Float, Numo::DFloat
Get in-the-money probability
178 179 180 181 182 183 184 185 186 187 188 189 |
# File 'lib/option_lab/black_scholes.rb', line 178 def get_itm_probability(option_type, d2, years_to_maturity, y = 0.0) yfac = Math.exp(-y * years_to_maturity) case option_type when 'call' yfac * Distribution::Normal.cdf(d2) when 'put' yfac * Distribution::Normal.cdf(-d2) else raise ArgumentError, "Option type must be either 'call' or 'put'!" end end |
.get_option_price(option_type, s0, x, r, years_to_maturity, d1, d2, y = 0.0) ⇒ Float, Numo::DFloat
Get option price using Black-Scholes formula
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
# File 'lib/option_lab/black_scholes.rb', line 55 def get_option_price(option_type, s0, x, r, years_to_maturity, d1, d2, y = 0.0) # First validate option type unless ['call', 'put'].include?(option_type) raise ArgumentError, "Option type must be either 'call' or 'put'!" end # Calculate normally s = s0 * Math.exp(-y * years_to_maturity) discount_factor = Math.exp(-r * years_to_maturity) case option_type when 'call' # Call option price: S * N(d1) - X * e^(-rT) * N(d2) (s * Distribution::Normal.cdf(d1)) - (x * discount_factor * Distribution::Normal.cdf(d2)) when 'put' # Put option price: X * e^(-rT) * N(-d2) - S * N(-d1) (x * discount_factor * Distribution::Normal.cdf(-d2)) - (s * Distribution::Normal.cdf(-d1)) end end |
.get_rho(option_type, x, r, years_to_maturity, d2) ⇒ Float, Numo::DFloat
Get option rho
161 162 163 164 165 166 167 168 169 170 |
# File 'lib/option_lab/black_scholes.rb', line 161 def get_rho(option_type, x, r, years_to_maturity, d2) case option_type when 'call' x * years_to_maturity * Math.exp(-r * years_to_maturity) * Distribution::Normal.cdf(d2) / 100 when 'put' -x * years_to_maturity * Math.exp(-r * years_to_maturity) * Distribution::Normal.cdf(-d2) / 100 else raise ArgumentError, "Option type must be either 'call' or 'put'!" end end |
.get_theta(option_type, s0, x, r, vol, years_to_maturity, d1, d2, y = 0.0) ⇒ Float, Numo::DFloat
Get option theta
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
# File 'lib/option_lab/black_scholes.rb', line 121 def get_theta(option_type, s0, x, r, vol, years_to_maturity, d1, d2, y = 0.0) s = s0 * Math.exp(-y * years_to_maturity) # PDF of d1 cdf_d1_prime = Math.exp(-0.5 * d1 * d1) / Math.sqrt(2.0 * Math::PI) common_term = -(s * vol * cdf_d1_prime / (2.0 * Math.sqrt(years_to_maturity))) case option_type when 'call' common_term - (r * x * Math.exp(-r * years_to_maturity) * Distribution::Normal.cdf(d2)) + (y * s * Distribution::Normal.cdf(d1)) when 'put' common_term + (r * x * Math.exp(-r * years_to_maturity) * Distribution::Normal.cdf(-d2)) - (y * s * Distribution::Normal.cdf(-d1)) else raise ArgumentError, "Option type must be either 'call' or 'put'!" end end |
.get_vega(s0, years_to_maturity, d1, y = 0.0) ⇒ Float, Numo::DFloat
Get option vega
145 146 147 148 149 150 151 152 |
# File 'lib/option_lab/black_scholes.rb', line 145 def get_vega(s0, years_to_maturity, d1, y = 0.0) s = s0 * Math.exp(-y * years_to_maturity) # PDF of d1 cdf_d1_prime = Math.exp(-0.5 * d1 * d1) / Math.sqrt(2.0 * Math::PI) s * cdf_d1_prime * Math.sqrt(years_to_maturity) / 100 end |