greeks 1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 0d3ca525eaf15c5be09d9cdba6adc4dfd619089d
4
+ data.tar.gz: e991c828fbdaaff0d99a23e3137115136bd00b5c
5
+ SHA512:
6
+ metadata.gz: c76eff692a4ee4d8710f39a7c3c121133227f67bbc50ee8d3126c22946a17f6b41509a3ca7c79294335b4799ea2f4e54afc50057c4ea6a4343bb925ac0429a49
7
+ data.tar.gz: 501bfefa7861518237aab7c7cb3187598264fec413c27ec7b345f08267d4e3f830ff3d394e1091553dbc8730ed8e4a6545d850e272b7f9609a51b91aa980b06f
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ coverage
6
+ InstalledFiles
7
+ lib/bundler/man
8
+ pkg
9
+ rdoc
10
+ spec/reports
11
+ test/tmp
12
+ test/version_tmp
13
+ tmp
14
+
15
+ # YARD artifacts
16
+ .yardoc
17
+ _yardoc
18
+ doc/
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in *.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,29 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ greeks (1.0)
5
+ hash_plus
6
+ require_all
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ diff-lcs (1.2.4)
12
+ hash_plus (1.1)
13
+ require_all (1.2.1)
14
+ rspec (2.13.0)
15
+ rspec-core (~> 2.13.0)
16
+ rspec-expectations (~> 2.13.0)
17
+ rspec-mocks (~> 2.13.0)
18
+ rspec-core (2.13.1)
19
+ rspec-expectations (2.13.0)
20
+ diff-lcs (>= 1.1.3, < 2.0)
21
+ rspec-mocks (2.13.1)
22
+
23
+ PLATFORMS
24
+ ruby
25
+
26
+ DEPENDENCIES
27
+ greeks!
28
+ rspec
29
+ rspec-expectations
data/README.md ADDED
@@ -0,0 +1,4 @@
1
+ greeks
2
+ ======
3
+
4
+ Calculate greeks for options trading (Implied Volatility, Delta, Gamma, Vega, Rho, and Theta)
data/greeks.gemspec ADDED
@@ -0,0 +1,27 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "greeks/version"
4
+
5
+ Gem::Specification.new do |gem|
6
+ gem.name = "greeks"
7
+ gem.version = Math::Greeks::VERSION
8
+ gem.authors = ["Glenn Nagel"]
9
+ gem.email = ["glenn@mercury-wireless.com"]
10
+ gem.homepage = "https://github.com/gnagel/greeks"
11
+ gem.summary = %q{Calculate greeks for options trading (Implied Volatility, Delta, Gamma, Vega, Rho, and Theta)}
12
+ gem.description = %q{Calculate greeks (iv, delta, gamma, vega, rho, theta)}
13
+ gem.license = 'MIT'
14
+
15
+
16
+ gem.files = `git ls-files`.split($/)
17
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
18
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
19
+ gem.require_paths = ["lib", "tasks"]
20
+
21
+ # System
22
+ gem.add_dependency('require_all')
23
+ gem.add_dependency('hash_plus')
24
+
25
+ gem.add_development_dependency('rspec')
26
+ gem.add_development_dependency('rspec-expectations')
27
+ end
@@ -0,0 +1,29 @@
1
+ module Math
2
+ module GreekCalculations
3
+ # Delta
4
+ # A measurement of the change in the price of an option resulting from a change in the price of the underlying security.
5
+ # Delta is positive for calls and negative for puts. Delta can be calculated as the dollar change of the option that an
6
+ # investor can expect for a one-dollar change in the underlying security. For example, let's say an option on a stock
7
+ # trading at $50 costs $1 and has a delta of $0.50 per dollar of underlying stock price change. If the stock price rises
8
+ # to $52, the price of the option will increase by $1 (the $2 price change times the $0.50 delta). After the stock price
9
+ # movement, the option will be worth $2 ($1 initial cost plus $1 delta). Delta can also be calculated as a percentage
10
+ # change in the option price for a one-percent change in the underlying security; this method of viewing the delta value
11
+ # is also known as "leverage."
12
+ def delta(opts)
13
+ opts.requires_fields(:option_type, :rate_vs_expires, :d1_normal_distribution, :iv)
14
+
15
+ return nil if opts[:iv].nil?
16
+
17
+ multiplier = case opts[:option_type]
18
+ when :call
19
+ 1.0
20
+ when :put
21
+ -1.0
22
+ else
23
+ raise "Invalid option_type = #{opts[:option_type].inspect}"
24
+ end
25
+
26
+ multiplier * opts[:rate_vs_expires] * opts[:d1_normal_distribution]
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,19 @@
1
+ module Math
2
+ module GreekCalculations
3
+ # Gamma
4
+ # A measurement of the change in delta as the price of the underlying stock changes. As the underlying stock price changes,
5
+ # the delta of the option changes, too. Gamma indicates how quickly your exposure to the price movement of the underlying
6
+ # security changes as the price of the underlying security varies. For example, if you have a call with a strike of $50
7
+ # and the stock price is $50, the delta likely will be approximately $0.50 for a one-dollar movement of the stock.
8
+ # At a stock price of $60, the delta will be greater, closer to $0.75. At a stock price of $40, the delta will be less,
9
+ # closer to $0.25. In this example, if the stock price changes from $50 to $60, then the delta will change from $0.50 to $0.75.
10
+ # The $10 change in stock price caused a $0.25 change in delta, so gamma is approximately $0.25/10, or $0.025, in this case.
11
+ def gamma(opts = {})
12
+ opts.requires_fields(:stock_price, :option_expires_pct_year_sqrt, :iv, :nd1, :rate_vs_expires)
13
+
14
+ return nil if opts[:iv].nil?
15
+
16
+ opts[:nd1] * opts[:rate_vs_expires] / (opts[:stock_price] * opts[:iv] * opts[:option_expires_pct_year_sqrt])
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,117 @@
1
+ module Math
2
+ module GreekCalculations
3
+ def iv(opts)
4
+ opts.requires_fields(:stock_price, :option_strike, :option_expires_pct_year, :option_expires_pct_year_sqrt, :federal_reserve_interest_rate_f, :stock_dividend_rate_f, :option_type, :option_price, :rate_vs_expires, :price_vs_rate_vs_expires, :strike_vs_fed_vs_expires, :price_ratio_log_less_rates)
5
+
6
+ return nil if opts[:option_price].nil? || opts[:option_price] < 0
7
+
8
+ iv_calc(
9
+ opts[:stock_price],
10
+ opts[:option_strike],
11
+ opts[:option_expires_pct_year],
12
+ opts[:option_expires_pct_year_sqrt],
13
+ opts[:federal_reserve_interest_rate_f],
14
+ opts[:stock_dividend_rate_f],
15
+ opts[:option_type],
16
+ opts[:option_price],
17
+ opts[:price_vs_rate_vs_expires],
18
+ opts[:price_ratio_log_less_rates],
19
+ opts[:strike_vs_fed_vs_expires]
20
+ )
21
+ end
22
+
23
+
24
+ def iv_vega(stock_price, option_strike, option_expires_pct_year, option_expires_pct_year_sqrt, volatility_guess, federal_reserve_interest_rate_f, stock_dividend_rate_f, price_ratio_log_less_rates, price_vs_rate_vs_expires)
25
+ var_d1 = (price_ratio_log_less_rates + volatility_guess * volatility_guess * option_expires_pct_year / 2) / (volatility_guess * option_expires_pct_year_sqrt)
26
+ var_nd = Math.exp(-var_d1 * var_d1 / 2) / Math::sqrt(2 * Math::PI)
27
+ return price_vs_rate_vs_expires * option_expires_pct_year_sqrt * var_nd
28
+ end
29
+
30
+
31
+ def iv_option_price(stock_price, option_strike, option_expires_pct_year, option_expires_pct_year_sqrt, volatility_guess, federal_reserve_interest_rate_f, stock_dividend_rate_f, option_type, price_ratio_log_less_rates, price_vs_rate_vs_expires, strike_vs_fed_vs_expires)
32
+ var_d1 = (price_ratio_log_less_rates + volatility_guess * volatility_guess * option_expires_pct_year / 2) / (volatility_guess * option_expires_pct_year_sqrt)
33
+ var_d2 = var_d1 - volatility_guess * option_expires_pct_year_sqrt
34
+
35
+ case option_type
36
+ when :call
37
+ return price_vs_rate_vs_expires * normal_distribution(var_d1) - strike_vs_fed_vs_expires * normal_distribution(var_d2)
38
+ when :put
39
+ return strike_vs_fed_vs_expires * normal_distribution(-var_d2) - price_vs_rate_vs_expires * normal_distribution(-var_d1)
40
+ else
41
+ raise "Invalid option_type = #{option_type.inspect}"
42
+ end
43
+ end
44
+
45
+
46
+ def iv_volatility_guess0(stock_price, option_strike, option_expires_pct_year, federal_reserve_interest_rate_f, stock_dividend_rate_f)
47
+ Math.sqrt(
48
+ (Math.log(stock_price / option_strike) + (federal_reserve_interest_rate_f - stock_dividend_rate_f) * option_expires_pct_year).abs * 2 / option_expires_pct_year)
49
+ end
50
+
51
+
52
+ def iv_calc(stock_price, option_strike, option_expires_pct_year, option_expires_pct_year_sqrt, federal_reserve_interest_rate_f, stock_dividend_rate_f, option_type, option_price, price_vs_rate_vs_expires, price_ratio_log_less_rates, strike_vs_fed_vs_expires)
53
+ # Contstant values for the calculations
54
+ price_limit = [0.005, 0.01 * option_price].min
55
+
56
+ # Lambda for short-hand calculations
57
+ calc_option_price = lambda { |volatility_guess| iv_option_price(stock_price, option_strike, option_expires_pct_year, option_expires_pct_year_sqrt, volatility_guess, federal_reserve_interest_rate_f, stock_dividend_rate_f, option_type, price_ratio_log_less_rates, price_vs_rate_vs_expires, strike_vs_fed_vs_expires) }
58
+
59
+ # Lambda for short-hand calculations
60
+ calc_vega = lambda { |volatility_guess| iv_vega(stock_price, option_strike, option_expires_pct_year, option_expires_pct_year_sqrt, volatility_guess, federal_reserve_interest_rate_f, stock_dividend_rate_f, price_ratio_log_less_rates, price_vs_rate_vs_expires) }
61
+
62
+ # Lambda for short-hand calculations
63
+ calc_volatility_guess1 = lambda { |var_volatility_guess, var_option_price, var_vega| var_volatility_guess - (var_option_price - option_price) / var_vega }
64
+
65
+ # Lambda for short-hand calculations
66
+ is_terminal_volatility_guess = lambda { |var_option_price| ((option_price - var_option_price).abs < price_limit) }
67
+
68
+ # Lambda for short-hand calculations
69
+ cleanup_volatility_guess = lambda { |volatility_guess| volatility_guess.nil? || volatility_guess <= 0 ? nil : volatility_guess.to_f }
70
+
71
+ var_volatility_guess = iv_volatility_guess0(stock_price, option_strike, option_expires_pct_year, federal_reserve_interest_rate_f, stock_dividend_rate_f)
72
+ var_volatility_guess = 0.1 if var_volatility_guess <= 0
73
+ var_option_price = calc_option_price.call(var_volatility_guess)
74
+
75
+ if is_terminal_volatility_guess.call(var_option_price)
76
+ return cleanup_volatility_guess.call(var_volatility_guess)
77
+ end
78
+
79
+ var_vega = calc_vega.call(var_volatility_guess)
80
+
81
+ var_volatility_guess1 = calc_volatility_guess1.call(var_volatility_guess, var_option_price, var_vega)
82
+
83
+ var_step = 1
84
+ max_steps = 13
85
+ while ((var_volatility_guess - var_volatility_guess1).abs > 0.0001 && var_step < max_steps)
86
+ var_volatility_guess = var_volatility_guess1
87
+ var_option_price = calc_option_price.call(var_volatility_guess)
88
+
89
+ if is_terminal_volatility_guess.call(var_option_price)
90
+ return cleanup_volatility_guess.call(var_volatility_guess)
91
+ end
92
+
93
+ var_vega = calc_vega.call(var_volatility_guess)
94
+
95
+ var_volatility_guess1 = calc_volatility_guess1.call(var_volatility_guess, var_option_price, var_vega)
96
+ if (var_volatility_guess1 < 0)
97
+ return cleanup_volatility_guess.call(var_volatility_guess1)
98
+ end
99
+
100
+ var_step += 1
101
+ end
102
+
103
+ if (var_step < max_steps)
104
+ return cleanup_volatility_guess.call(var_volatility_guess1)
105
+ end
106
+
107
+ var_option_price = calc_option_price.call(var_volatility_guess1)
108
+
109
+ if is_terminal_volatility_guess.call(var_option_price)
110
+ return cleanup_volatility_guess.call(var_volatility_guess1)
111
+ else
112
+ return nil
113
+ end
114
+ end
115
+
116
+ end
117
+ end
@@ -0,0 +1,27 @@
1
+ module Math
2
+ module GreekCalculations
3
+ # Moddeled after the Excel NORMSDIST function
4
+ def normal_distribution(value)
5
+ p = 0.2316419
6
+ b1 = 0.319381530
7
+ b2 = -0.356563782
8
+ b3 = 1.781477937
9
+ b4 = -1.821255978
10
+ b5 = 1.330274429
11
+
12
+ y = value.abs
13
+ z = Math.exp(-y*y/2) / Math.sqrt(2 * Math::PI)
14
+ t = 1 / ( 1 + p * y)
15
+ cum = 1 - z * (b1*t + b2*t*t + b3*t*t*t + b4*t*t*t*t + b5*t*t*t*t*t)
16
+
17
+ cum = 1 - cum if (value < 0)
18
+ cum
19
+ end
20
+
21
+
22
+ # Normal distribution function (Gaussian bell curve)
23
+ def normal_distribution_gaussian(value)
24
+ Math.exp(-0.5 * value * value) / Math.sqrt(2 * Math::PI)
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,23 @@
1
+ module Math
2
+ module GreekCalculations
3
+ # Rho
4
+ # The change in the value of an option for a change in the prevailing interest rate that matches the duration of the option,
5
+ # all else held equal. Generally rho is not a big driver of price changes for options, as interest rates tend to be relatively stable.
6
+ def rho(opts = {})
7
+ opts.requires_fields(:option_type, :option_expires_pct_year, :strike_vs_fed_vs_expires, :d2_normal_distribution, :iv)
8
+
9
+ return nil if opts[:iv].nil?
10
+
11
+ multiplier = case opts[:option_type]
12
+ when :call
13
+ 1.0
14
+ when :put
15
+ -1.0
16
+ else
17
+ raise "Invalid option_type = #{opts[:option_type].inspect}"
18
+ end
19
+
20
+ multiplier * opts[:option_expires_pct_year] * opts[:strike_vs_fed_vs_expires] * opts[:d2_normal_distribution] / 100
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,23 @@
1
+ module Math
2
+ module GreekCalculations
3
+ def theta(opts = {})
4
+ opts.requires_fields(:stock_dividend_rate_f, :federal_reserve_interest_rate_f, :option_type, :option_expires_pct_year_sqrt, :iv, :strike_vs_fed_vs_expires, :price_vs_rate_vs_expires, :nd1, :d1_normal_distribution, :d2_normal_distribution)
5
+
6
+ return nil if opts[:iv].nil?
7
+
8
+ part0 = opts[:price_vs_rate_vs_expires] * opts[:nd1] * opts[:iv]
9
+ part1 = 2 * opts[:option_expires_pct_year_sqrt]
10
+ part2 = opts[:stock_dividend_rate_f] * opts[:price_vs_rate_vs_expires] * opts[:d1_normal_distribution]
11
+ part3 = opts[:federal_reserve_interest_rate_f] * opts[:strike_vs_fed_vs_expires] * opts[:d2_normal_distribution]
12
+
13
+ case opts[:option_type]
14
+ when :call
15
+ return (-part0 / part1 + part2 - part3) / 365
16
+ when :put
17
+ return (-part0 / part1 - part2 + part3) / 365
18
+ else
19
+ raise "Invalid option_type = #{opts[:option_type].inspect}"
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,181 @@
1
+ module Math
2
+ module GreekCalculations
3
+
4
+ def nil_or_gte0(value)
5
+ value.nil? || value.to_f < 0 ? nil : value
6
+ end
7
+
8
+
9
+ # Intrinsic Value
10
+ # The value that the option would pay if it were executed today. For example, if a stock is trading at $40,
11
+ # a call on that stock with a strike price of $35 would have $5 of intrinsic value ($40-$35) if it were
12
+ # exercised today. However, the call should actually be worth more than $5 to account for the value of the
13
+ # chance of any further appreciation until expiration, and the difference between the price and the
14
+ # intrinsic value would be the time value.
15
+ def premium_value(opts)
16
+ opts.requires_fields(:option_type, :option_strike, :stock_price)
17
+
18
+ case opts[:option_type]
19
+ when :call
20
+ return [opts[:stock_price] - opts[:option_strike], 0].max
21
+ when :put
22
+ return [opts[:option_strike] - opts[:stock_price], 0].max
23
+ else
24
+ raise ArgumentError, "Invalid option_type = #{opts[:option_type]}"
25
+ end
26
+ end
27
+
28
+
29
+ # Time Value
30
+ # The value of an option that captures the chance of further appreciation before expiration.
31
+ # The value of an option can be broken down into intrinsic value, or the value of the option
32
+ # if it were exercised today, and time value, or the added value of the option over and above
33
+ # the intrinsic value. For example, if a stock is trading at $40 and a call with a strike price
34
+ # of $35 were trading for $7, the call would have a $5 intrinsic value ($40-$35) and a $2 time value ($7-$5).
35
+ # Time value will decay by expiration assuming the underlying security stays at the same price.
36
+ def time_value(opts)
37
+ opts.requires_fields(:option_price, :premium_value)
38
+
39
+ return nil if opts[:option_price].nil?
40
+ return nil if opts[:option_price] < 0
41
+
42
+ nil_or_gte0(opts[:option_price] - opts[:premium_value])
43
+ end
44
+
45
+
46
+ # Annualized Premium
47
+ # The annualized premium is the value of the option divided by the strike price. You can use annualized
48
+ # premium to develop an intuitive understanding of how much the market is "paying" for a dollar of risk.
49
+ # For example, if a stock is trading at $50 and you sell a $50 strike 6 month call for $4, you are getting
50
+ # paid 8% in 6 months, or about 16% annualized, in exchange for being willing to buy at $50, the current price.
51
+ def annualized_premium_value
52
+ opts.requires_fields(:option_price, :option_strike, :option_expires_pct_year)
53
+
54
+ return nil if opts[:option_price].nil?
55
+ return nil if opts[:option_price] < 0
56
+
57
+ nil_or_gte0(100 * Math.log(1 + opts[:option_price] / opts[:option_strike]) / opts[:option_expires_pct_year])
58
+ end
59
+
60
+
61
+ # Annualized Time Value
62
+ # The time value of the option divided by the strike price, then annualized. You can use annualized
63
+ # time value to develop an intuitive understanding of how much value the option market is adding to
64
+ # an in-the-money option beyond the intrinsic value. For example, if a stock is trading at $40 and a
65
+ # six month call on that stock with a strike price of $35 has an intrinsic value of $5 and a total
66
+ # value of $7, the time value ($2) divided by the strike is ($2/$40) = 5%. Annualizing that time value
67
+ # to a one year horizon on a continuously compounded basis yields 9.76% (2 × ln(1 + 0.05)).
68
+ def annualized_time_value
69
+ opts.requires_fields(:option_strike, :option_expires_pct_year, :time_value)
70
+
71
+ return nil if opts[:time_value].nil?
72
+
73
+ nil_or_gte0(100 * Math.log(1.0 + opts[:time_value] / opts[:option_strike]) / opts[:option_expires_pct_year])
74
+ end
75
+
76
+
77
+ # Chance of Breakeven
78
+ # The probability that a stock will be trading beyond the breakeven price as implied by the option price.
79
+ # Chance of Breakeven can be used to get a sense for the valuation of the option by comparing the markets'
80
+ # estimate of Chance of Breakeven to estimates derived from your own fundamental research.
81
+ # If you believe the Chance of Breakeven is less than the probability that a stock will be beyond the
82
+ # breakeven price at option expiration, then you believe the option is undervalued, and visa versa.
83
+ def break_even(opts)
84
+ opts.requires_fields(:option_type, :option_price, :option_strike, :option_expires_pct_year, :option_expires_pct_year_sqrt, :stock_price, :stock_dividend_rate_f, :federal_reserve_interest_rate_f, :iv)
85
+
86
+ return nil if opts[:option_price].nil?
87
+ return nil if opts[:option_price] < 0
88
+ return nil if opts[:iv].nil?
89
+
90
+ part1 = (opts[:federal_reserve_interest_rate_f] - opts[:stock_dividend_rate_f] - opts[:iv] * opts[:iv] / 2) * opts[:option_expires_pct_year]
91
+ part2 = opts[:iv] * opts[:option_expires_pct_year_sqrt]
92
+
93
+ case opts[:option_type]
94
+ when :call
95
+ return normal_distribution((Math.log(opts[:stock_price] / (opts[:option_strike] + opts[:option_price])) + part1) / part2)
96
+ when :put
97
+ return normal_distribution(-(Math.log(opts[:stock_price] / (opts[:option_strike] - opts[:option_price])) + part1) / part2)
98
+ else
99
+ raise ArgumentError, "Invalid option_type = #{opts[:option_type]}"
100
+ end
101
+ end
102
+
103
+
104
+ #####
105
+ # Misc calculations
106
+ #####
107
+
108
+
109
+ def misc_price_ratio_log_less_rates(opts)
110
+ opts.requires_fields(:stock_price, :option_strike, :option_expires_pct_year, :federal_reserve_interest_rate_f, :stock_dividend_rate_f)
111
+
112
+ Math.log(opts[:stock_price] / opts[:option_strike]) + (opts[:federal_reserve_interest_rate_f] - opts[:stock_dividend_rate_f]) * opts[:option_expires_pct_year]
113
+ end
114
+
115
+
116
+ def misc_rate_vs_expires(opts)
117
+ opts.requires_fields(:option_expires_pct_year, :stock_dividend_rate_f)
118
+
119
+ Math.exp(opts[:option_expires_pct_year] * -opts[:stock_dividend_rate_f])
120
+ end
121
+
122
+
123
+ def misc_price_vs_rate_vs_expires(opts)
124
+ opts.requires_fields(:stock_price, :option_expires_pct_year, :stock_dividend_rate_f)
125
+
126
+ opts[:stock_price] * misc_rate_vs_expires(opts)
127
+ end
128
+
129
+
130
+ def misc_strike_vs_fed_vs_expires(opts)
131
+ opts.requires_fields(:option_strike, :option_expires_pct_year, :federal_reserve_interest_rate_f)
132
+
133
+ opts[:option_strike] * Math.exp(opts[:option_expires_pct_year] * -opts[:federal_reserve_interest_rate_f])
134
+ end
135
+
136
+
137
+ def misc_nd1(opts)
138
+ opts.requires_fields(:d1)
139
+
140
+ return nil if opts[:d1].nil?
141
+
142
+ Math.exp(-0.5 * opts[:d1] * opts[:d1]) / Math.sqrt(2 * Math::PI)
143
+ end
144
+
145
+
146
+ def misc_d1(opts)
147
+ opts.requires_fields(:price_ratio_log_less_rates, :iv, :option_expires_pct_year, :option_expires_pct_year_sqrt)
148
+
149
+ return nil if opts[:iv].nil?
150
+
151
+ (opts[:price_ratio_log_less_rates] + opts[:iv] * opts[:iv] * opts[:option_expires_pct_year] / 2) / (opts[:iv] * opts[:option_expires_pct_year_sqrt])
152
+ end
153
+
154
+
155
+ def misc_d2(opts)
156
+ opts.requires_fields(:d1, :iv, :option_expires_pct_year_sqrt)
157
+
158
+ return nil if opts[:iv].nil?
159
+
160
+ opts[:d1] - opts[:iv] * opts[:option_expires_pct_year_sqrt]
161
+ end
162
+
163
+ def misc_d_normal_distribution(opts)
164
+ opts.requires_fields(:option_type, :d_value)
165
+
166
+ return nil if opts[:d_value].nil?
167
+
168
+ multiplier = case opts[:option_type]
169
+ when :call
170
+ 1.0
171
+ when :put
172
+ -1.0
173
+ else
174
+ raise ArgumentError, "Invalid option_type = #{opts[:option_type]}"
175
+ end
176
+
177
+ normal_distribution(multiplier * opts[:d_value])
178
+ end
179
+
180
+ end
181
+ end
@@ -0,0 +1,17 @@
1
+ module Math
2
+ module GreekCalculations
3
+ # Vega
4
+ # The change in the price of an option for a change in the implied volatility of the option, all else held equal.
5
+ # In general, as the options market thinks it is more difficult to value a stock, implied volatility and therefore
6
+ # the price of the options will increase. For example, if an option is trading for $1, the implied volatility is 20%,
7
+ # and the vega is $0.05, then a one-percentage-point increase in implied volatility to 21% would correspond to an increase in
8
+ # the price of the option to $1.05. In percentage terms, the vega in this case would be ($0.05/$1.00)/(1 percentage point) = 5%.
9
+ def vega(opts = {})
10
+ opts.requires_fields(:price_vs_rate_vs_expires, :nd1, :option_expires_pct_year_sqrt, :iv)
11
+
12
+ return nil if opts[:iv].nil?
13
+
14
+ opts[:price_vs_rate_vs_expires] * opts[:option_expires_pct_year_sqrt] * opts[:nd1] / 100
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,5 @@
1
+ module Math
2
+ module Greeks
3
+ VERSION = '1.0'
4
+ end
5
+ end