greeks 1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +29 -0
- data/README.md +4 -0
- data/greeks.gemspec +27 -0
- data/lib/greeks/calculations/delta.rb +29 -0
- data/lib/greeks/calculations/gamma.rb +19 -0
- data/lib/greeks/calculations/iv.rb +117 -0
- data/lib/greeks/calculations/normal_distribution.rb +27 -0
- data/lib/greeks/calculations/rho.rb +23 -0
- data/lib/greeks/calculations/theta.rb +23 -0
- data/lib/greeks/calculations/time_values.rb +181 -0
- data/lib/greeks/calculations/vega.rb +17 -0
- data/lib/greeks/version.rb +5 -0
- data/lib/greeks.rb +371 -0
- data/spec/greeks/calculations/delta_spec.rb +9 -0
- data/spec/greeks/calculations/gamma_spec.rb +8 -0
- data/spec/greeks/calculations/iv_option_price_spec.rb +67 -0
- data/spec/greeks/calculations/iv_spec.rb +56 -0
- data/spec/greeks/calculations/iv_vega_spec.rb +66 -0
- data/spec/greeks/calculations/normal_distribution_spec.rb +22 -0
- data/spec/greeks/calculations/rho_spec.rb +9 -0
- data/spec/greeks/calculations/theta_spec.rb +10 -0
- data/spec/greeks/calculations/time_values_spec.rb +79 -0
- data/spec/greeks/calculations/vega_spec.rb +10 -0
- data/spec/greeks/greeks_spec.rb +110 -0
- data/spec/spec_helper.rb +89 -0
- metadata +141 -0
data/lib/greeks.rb
ADDED
@@ -0,0 +1,371 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'hash_plus'
|
3
|
+
|
4
|
+
require_relative 'greeks/calculations/delta'
|
5
|
+
require_relative 'greeks/calculations/gamma'
|
6
|
+
require_relative 'greeks/calculations/iv'
|
7
|
+
require_relative 'greeks/calculations/normal_distribution'
|
8
|
+
require_relative 'greeks/calculations/theta'
|
9
|
+
require_relative 'greeks/calculations/rho'
|
10
|
+
require_relative 'greeks/calculations/vega'
|
11
|
+
require_relative 'greeks/calculations/time_values'
|
12
|
+
require_relative 'greeks/version'
|
13
|
+
|
14
|
+
|
15
|
+
module Math
|
16
|
+
module Greeks
|
17
|
+
class Calculator
|
18
|
+
class GreekCalculations
|
19
|
+
extend Math::GreekCalculations
|
20
|
+
end
|
21
|
+
|
22
|
+
attr_reader :stock_price
|
23
|
+
attr_reader :stock_dividend_rate
|
24
|
+
attr_reader :option_type # :call, or :put
|
25
|
+
attr_reader :option_price # bid, mid, or ask
|
26
|
+
attr_reader :option_strike
|
27
|
+
attr_reader :option_expires_in_days
|
28
|
+
attr_reader :federal_reserve_interest_rate
|
29
|
+
|
30
|
+
attr_reader :option_expires_pct_year
|
31
|
+
attr_reader :option_expires_pct_year_sqrt
|
32
|
+
attr_reader :stock_dividend_rate_f
|
33
|
+
attr_reader :federal_reserve_interest_rate_f
|
34
|
+
attr_reader :rate_vs_expires
|
35
|
+
attr_reader :price_vs_rate_vs_expires
|
36
|
+
attr_reader :strike_vs_fed_vs_expires
|
37
|
+
attr_reader :price_ratio_log_less_rates
|
38
|
+
|
39
|
+
|
40
|
+
def initialize(opts)
|
41
|
+
@stock_price = opts[:stock_price]
|
42
|
+
@stock_dividend_rate = opts[:stock_dividend_rate]
|
43
|
+
@option_type = opts[:option_type]
|
44
|
+
@option_price = opts[:option_price]
|
45
|
+
@option_strike = opts[:option_strike]
|
46
|
+
@option_expires_in_days = opts[:option_expires_in_days]
|
47
|
+
@federal_reserve_interest_rate = opts[:federal_reserve_interest_rate]
|
48
|
+
|
49
|
+
@federal_reserve_interest_rate_f = federal_reserve_interest_rate / 100.0
|
50
|
+
@stock_dividend_rate_f = stock_dividend_rate / 100.0
|
51
|
+
@option_expires_pct_year = (option_expires_in_days + 1.0) / 365.0
|
52
|
+
@option_expires_pct_year_sqrt = Math.sqrt(option_expires_pct_year)
|
53
|
+
|
54
|
+
|
55
|
+
@price_vs_rate_vs_expires = GreekCalculations.misc_price_vs_rate_vs_expires(
|
56
|
+
:stock_price => stock_price,
|
57
|
+
:stock_dividend_rate_f => stock_dividend_rate_f,
|
58
|
+
:option_expires_pct_year => option_expires_pct_year
|
59
|
+
)
|
60
|
+
|
61
|
+
@rate_vs_expires = GreekCalculations.misc_rate_vs_expires(
|
62
|
+
:option_expires_pct_year => option_expires_pct_year,
|
63
|
+
:stock_dividend_rate_f => stock_dividend_rate_f
|
64
|
+
)
|
65
|
+
|
66
|
+
@strike_vs_fed_vs_expires = GreekCalculations.misc_strike_vs_fed_vs_expires(
|
67
|
+
:option_strike => option_strike,
|
68
|
+
:option_expires_pct_year => option_expires_pct_year,
|
69
|
+
:federal_reserve_interest_rate_f => federal_reserve_interest_rate_f
|
70
|
+
)
|
71
|
+
|
72
|
+
@price_ratio_log_less_rates = GreekCalculations.misc_price_ratio_log_less_rates(
|
73
|
+
:stock_price => stock_price,
|
74
|
+
:stock_dividend_rate_f => stock_dividend_rate_f,
|
75
|
+
:option_strike => option_strike,
|
76
|
+
:option_expires_pct_year => option_expires_pct_year,
|
77
|
+
:federal_reserve_interest_rate_f => federal_reserve_interest_rate_f
|
78
|
+
)
|
79
|
+
end
|
80
|
+
|
81
|
+
|
82
|
+
# Chance of Breakeven
|
83
|
+
# The probability that a stock will be trading beyond the breakeven price as implied by the option price.
|
84
|
+
# Chance of Breakeven can be used to get a sense for the valuation of the option by comparing the markets'
|
85
|
+
# estimate of Chance of Breakeven to estimates derived from your own fundamental research.
|
86
|
+
# If you believe the Chance of Breakeven is less than the probability that a stock will be beyond the
|
87
|
+
# breakeven price at option expiration, then you believe the option is undervalued, and visa versa.
|
88
|
+
def break_even
|
89
|
+
@break_even ||= GreekCalculations.break_even(
|
90
|
+
:stock_price => stock_price,
|
91
|
+
:stock_dividend_rate_f => stock_dividend_rate_f,
|
92
|
+
:federal_reserve_interest_rate_f => federal_reserve_interest_rate_f,
|
93
|
+
:option_type => option_type,
|
94
|
+
:option_price => option_price,
|
95
|
+
:option_strike => option_strike,
|
96
|
+
:option_expires_pct_year => option_expires_pct_year,
|
97
|
+
:option_expires_pct_year_sqrt => option_expires_pct_year_sqrt,
|
98
|
+
:iv => iv
|
99
|
+
)
|
100
|
+
end
|
101
|
+
|
102
|
+
|
103
|
+
# Intrinsic Value
|
104
|
+
# The value that the option would pay if it were executed today. For example, if a stock is trading at $40,
|
105
|
+
# a call on that stock with a strike price of $35 would have $5 of intrinsic value ($40-$35) if it were
|
106
|
+
# exercised today. However, the call should actually be worth more than $5 to account for the value of the
|
107
|
+
# chance of any further appreciation until expiration, and the difference between the price and the
|
108
|
+
# intrinsic value would be the time value.
|
109
|
+
def premium_value
|
110
|
+
@premium_value ||= GreekCalculations.premium_value(
|
111
|
+
:option_type => option_type,
|
112
|
+
:option_strike => option_strike,
|
113
|
+
:stock_price => stock_price
|
114
|
+
)
|
115
|
+
end
|
116
|
+
|
117
|
+
|
118
|
+
# Time Value
|
119
|
+
# The value of an option that captures the chance of further appreciation before expiration.
|
120
|
+
# The value of an option can be broken down into intrinsic value, or the value of the option
|
121
|
+
# if it were exercised today, and time value, or the added value of the option over and above
|
122
|
+
# the intrinsic value. For example, if a stock is trading at $40 and a call with a strike price
|
123
|
+
# of $35 were trading for $7, the call would have a $5 intrinsic value ($40-$35) and a $2 time value ($7-$5).
|
124
|
+
# Time value will decay by expiration assuming the underlying security stays at the same price.
|
125
|
+
def time_value
|
126
|
+
@time_value ||= GreekCalculations.time_value(
|
127
|
+
:option_price => option_price,
|
128
|
+
:premium_value => premium_value
|
129
|
+
)
|
130
|
+
end
|
131
|
+
|
132
|
+
|
133
|
+
# Annualized Premium
|
134
|
+
# The annualized premium is the value of the option divided by the strike price. You can use annualized
|
135
|
+
# premium to develop an intuitive understanding of how much the market is "paying" for a dollar of risk.
|
136
|
+
# For example, if a stock is trading at $50 and you sell a $50 strike 6 month call for $4, you are getting
|
137
|
+
# paid 8% in 6 months, or about 16% annualized, in exchange for being willing to buy at $50, the current price.
|
138
|
+
def annualized_premium_value
|
139
|
+
@annualized_premium_value ||= GreekCalculations.annualized_premium_value(
|
140
|
+
:option_price => option_price,
|
141
|
+
:option_strike => option_strike,
|
142
|
+
:option_expires_pct_year => option_expires_pct_year
|
143
|
+
)
|
144
|
+
end
|
145
|
+
|
146
|
+
|
147
|
+
# Annualized Time Value
|
148
|
+
# The time value of the option divided by the strike price, then annualized. You can use annualized
|
149
|
+
# time value to develop an intuitive understanding of how much value the option market is adding to
|
150
|
+
# an in-the-money option beyond the intrinsic value. For example, if a stock is trading at $40 and a
|
151
|
+
# six month call on that stock with a strike price of $35 has an intrinsic value of $5 and a total
|
152
|
+
# value of $7, the time value ($2) divided by the strike is ($2/$40) = 5%. Annualizing that time value
|
153
|
+
# to a one year horizon on a continuously compounded basis yields 9.76% (2 × ln(1 + 0.05)).
|
154
|
+
def annualized_time_value
|
155
|
+
@annualized_time_value ||= GreekCalculations.annualized_time_value(
|
156
|
+
:time_value => time_value,
|
157
|
+
:option_strike => option_strike,
|
158
|
+
:option_expires_pct_year => option_expires_pct_year
|
159
|
+
)
|
160
|
+
end
|
161
|
+
|
162
|
+
|
163
|
+
# Implied Volatility
|
164
|
+
# A measure of the "riskiness" of the underlying security. Implied volatility is the primary measure of
|
165
|
+
# the "price" of an option--how expensive it is relative to other options. It is the "plug" value in option
|
166
|
+
# pricing models (the only variable in the equation that isn't precisely known). The remaining variables are
|
167
|
+
# option price, stock price, strike price, time to expiration, interest rate, and estimated dividends.
|
168
|
+
# Therefore, the implied volatility is the component of the option price that is determined by the market.
|
169
|
+
# Implied volatility is greater if the future outcome of the underlying stock price is more uncertain.
|
170
|
+
# All else equal, the wider the market expects the range of possible outcomes to be for a stock's price,
|
171
|
+
# the higher the implied volatility, and the more expensive the option.
|
172
|
+
def iv
|
173
|
+
@iv ||= GreekCalculations.iv(
|
174
|
+
:stock_price => stock_price,
|
175
|
+
:stock_dividend_rate => stock_dividend_rate,
|
176
|
+
:stock_dividend_rate_f => stock_dividend_rate_f,
|
177
|
+
:option_type => option_type,
|
178
|
+
:option_price => option_price,
|
179
|
+
:option_strike => option_strike,
|
180
|
+
:option_expires_in_days => option_expires_in_days,
|
181
|
+
:option_expires_pct_year => option_expires_pct_year,
|
182
|
+
:option_expires_pct_year_sqrt => option_expires_pct_year_sqrt,
|
183
|
+
:federal_reserve_interest_rate => federal_reserve_interest_rate,
|
184
|
+
:federal_reserve_interest_rate_f => federal_reserve_interest_rate_f,
|
185
|
+
:price_ratio_log_less_rates => price_ratio_log_less_rates,
|
186
|
+
:rate_vs_expires => rate_vs_expires,
|
187
|
+
:strike_vs_fed_vs_expires => strike_vs_fed_vs_expires,
|
188
|
+
:price_vs_rate_vs_expires => price_vs_rate_vs_expires,
|
189
|
+
)
|
190
|
+
end
|
191
|
+
|
192
|
+
|
193
|
+
# Delta
|
194
|
+
# A measurement of the change in the price of an option resulting from a change in the price of the underlying security.
|
195
|
+
# Delta is positive for calls and negative for puts. Delta can be calculated as the dollar change of the option that an
|
196
|
+
# investor can expect for a one-dollar change in the underlying security. For example, let's say an option on a stock
|
197
|
+
# trading at $50 costs $1 and has a delta of $0.50 per dollar of underlying stock price change. If the stock price rises
|
198
|
+
# to $52, the price of the option will increase by $1 (the $2 price change times the $0.50 delta). After the stock price
|
199
|
+
# movement, the option will be worth $2 ($1 initial cost plus $1 delta). Delta can also be calculated as a percentage
|
200
|
+
# change in the option price for a one-percent change in the underlying security; this method of viewing the delta value
|
201
|
+
# is also known as "leverage."
|
202
|
+
def delta
|
203
|
+
@delta ||= GreekCalculations.delta(
|
204
|
+
:option_type => option_type,
|
205
|
+
:iv => iv,
|
206
|
+
:rate_vs_expires => rate_vs_expires,
|
207
|
+
:d1_normal_distribution => d1_normal_distribution
|
208
|
+
)
|
209
|
+
end
|
210
|
+
|
211
|
+
|
212
|
+
# Gamma
|
213
|
+
# A measurement of the change in delta as the price of the underlying stock changes. As the underlying stock price changes,
|
214
|
+
# the delta of the option changes, too. Gamma indicates how quickly your exposure to the price movement of the underlying
|
215
|
+
# security changes as the price of the underlying security varies. For example, if you have a call with a strike of $50
|
216
|
+
# and the stock price is $50, the delta likely will be approximately $0.50 for a one-dollar movement of the stock.
|
217
|
+
# 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,
|
218
|
+
# 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.
|
219
|
+
# 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.
|
220
|
+
def gamma
|
221
|
+
@gamma ||= GreekCalculations.gamma(
|
222
|
+
:stock_price => stock_price,
|
223
|
+
:option_expires_pct_year_sqrt => option_expires_pct_year_sqrt,
|
224
|
+
:iv => iv,
|
225
|
+
:nd1 => nd1,
|
226
|
+
:rate_vs_expires => rate_vs_expires
|
227
|
+
)
|
228
|
+
end
|
229
|
+
|
230
|
+
|
231
|
+
# Vega
|
232
|
+
# The change in the price of an option for a change in the implied volatility of the option, all else held equal.
|
233
|
+
# In general, as the options market thinks it is more difficult to value a stock, implied volatility and therefore
|
234
|
+
# the price of the options will increase. For example, if an option is trading for $1, the implied volatility is 20%,
|
235
|
+
# and the vega is $0.05, then a one-percentage-point increase in implied volatility to 21% would correspond to an increase in
|
236
|
+
# 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%.
|
237
|
+
def vega
|
238
|
+
@vega ||= GreekCalculations.vega(
|
239
|
+
:price_vs_rate_vs_expires => price_vs_rate_vs_expires,
|
240
|
+
:option_expires_pct_year_sqrt => option_expires_pct_year_sqrt,
|
241
|
+
:nd1 => nd1,
|
242
|
+
:iv => iv
|
243
|
+
)
|
244
|
+
end
|
245
|
+
|
246
|
+
|
247
|
+
# Rho
|
248
|
+
# The change in the value of an option for a change in the prevailing interest rate that matches the duration of the option,
|
249
|
+
# all else held equal. Generally rho is not a big driver of price changes for options, as interest rates tend to be relatively stable.
|
250
|
+
def rho
|
251
|
+
@rho ||= GreekCalculations.rho(
|
252
|
+
:option_type => option_type,
|
253
|
+
:option_expires_pct_year => option_expires_pct_year,
|
254
|
+
:strike_vs_fed_vs_expires => strike_vs_fed_vs_expires,
|
255
|
+
:d2_normal_distribution => d2_normal_distribution,
|
256
|
+
:iv => iv
|
257
|
+
)
|
258
|
+
end
|
259
|
+
|
260
|
+
|
261
|
+
# Theta
|
262
|
+
# The change in an option's value that an investor can expect from the passage of one day, assuming nothing else changes.
|
263
|
+
# Theta can be calculated in two ways, as the dollar change of the option that an investor can expect for a one-day passage of time,
|
264
|
+
# all else remaining equal, or as a percentage change in the option price for a one-day passage of time, all else remaining equal.
|
265
|
+
# For example, if an option trades at $1 on Monday morning and it has a theta of -$0.10 per day, you can expect the option to trade
|
266
|
+
# at $0.90 on Tuesday morning. Another way of measuring theta for that option is ($0.90 - $1)/$1 or -10% per day.
|
267
|
+
def theta
|
268
|
+
@theta ||= GreekCalculations.theta(
|
269
|
+
:federal_reserve_interest_rate_f => federal_reserve_interest_rate_f,
|
270
|
+
:stock_dividend_rate_f => stock_dividend_rate_f,
|
271
|
+
:option_type => option_type,
|
272
|
+
:option_expires_pct_year_sqrt => option_expires_pct_year_sqrt,
|
273
|
+
:strike_vs_fed_vs_expires => strike_vs_fed_vs_expires,
|
274
|
+
:price_vs_rate_vs_expires => price_vs_rate_vs_expires,
|
275
|
+
:price_ratio_log_less_rates => price_ratio_log_less_rates,
|
276
|
+
:iv => iv,
|
277
|
+
:nd1 => nd1,
|
278
|
+
:d1_normal_distribution => d1_normal_distribution,
|
279
|
+
:d2_normal_distribution => d2_normal_distribution
|
280
|
+
)
|
281
|
+
end
|
282
|
+
|
283
|
+
|
284
|
+
def to_hash
|
285
|
+
hash = {
|
286
|
+
:federal_reserve_interest_rate => federal_reserve_interest_rate,
|
287
|
+
:stock_dividend_rate => stock_dividend_rate,
|
288
|
+
:stock_price => stock_price,
|
289
|
+
:option_expires_in_days => option_expires_in_days,
|
290
|
+
:option_type => option_type,
|
291
|
+
:option_strike => option_strike,
|
292
|
+
:option_price => option_price,
|
293
|
+
:break_even => nil,
|
294
|
+
:iv => nil,
|
295
|
+
:delta => nil,
|
296
|
+
:gamma => nil,
|
297
|
+
:vega => nil,
|
298
|
+
:rho => nil,
|
299
|
+
:theta => nil,
|
300
|
+
:deta_vs_theta => nil,
|
301
|
+
}
|
302
|
+
hash[:break_even] = break_even * 100 unless break_even.nil?
|
303
|
+
hash[:iv] = iv * 100 unless iv.nil?
|
304
|
+
hash[:delta] = delta * stock_price / option_price unless delta.nil?
|
305
|
+
hash[:gamma] = gamma * stock_price / delta unless gamma.nil?
|
306
|
+
hash[:vega] = vega * iv * 100 / option_price unless vega.nil?
|
307
|
+
hash[:rho] = rho * 100 / option_price unless rho.nil?
|
308
|
+
hash[:theta] = theta * 100 / option_price unless theta.nil?
|
309
|
+
|
310
|
+
|
311
|
+
# Delta/Theta
|
312
|
+
# A measure of the “bang for the buck” of an option.
|
313
|
+
# By dividing the dimensionless Delta or leverage of an option by the dimensionless Theta or
|
314
|
+
# decay rate, the trend in the Delta/Theta column indicates which options give the most exposure
|
315
|
+
# to the movement of the underlying stock or index for a given decay rate of the option value.
|
316
|
+
# The highest numbers indicate the most bang for the buck for the least decay rate.
|
317
|
+
hash[:deta_vs_theta] = hash[:delta] / hash[:theta] unless hash[:delta].nil? || hash[:theta].nil?
|
318
|
+
|
319
|
+
[:iv, :delta, :gamma, :vega, :rho, :theta, :deta_vs_theta].each do |key|
|
320
|
+
hash[key] &&= hash[key].round(2)
|
321
|
+
end
|
322
|
+
|
323
|
+
hash
|
324
|
+
end
|
325
|
+
|
326
|
+
|
327
|
+
private
|
328
|
+
|
329
|
+
|
330
|
+
def d1
|
331
|
+
@d1 ||= GreekCalculations.misc_d1(
|
332
|
+
:price_ratio_log_less_rates => price_ratio_log_less_rates,
|
333
|
+
:option_expires_pct_year => option_expires_pct_year,
|
334
|
+
:option_expires_pct_year_sqrt => option_expires_pct_year_sqrt,
|
335
|
+
:iv => iv
|
336
|
+
)
|
337
|
+
end
|
338
|
+
|
339
|
+
|
340
|
+
def d2
|
341
|
+
@d2 ||= GreekCalculations.misc_d2(
|
342
|
+
:option_expires_pct_year_sqrt => option_expires_pct_year_sqrt,
|
343
|
+
:d1 => d1,
|
344
|
+
:iv => iv
|
345
|
+
)
|
346
|
+
end
|
347
|
+
|
348
|
+
|
349
|
+
def d1_normal_distribution
|
350
|
+
@d1_normal_distribution ||= GreekCalculations.misc_d_normal_distribution(
|
351
|
+
:option_type => option_type,
|
352
|
+
:d_value => d1
|
353
|
+
)
|
354
|
+
end
|
355
|
+
|
356
|
+
|
357
|
+
def d2_normal_distribution
|
358
|
+
@d2_normal_distribution ||= GreekCalculations.misc_d_normal_distribution(
|
359
|
+
:option_type => option_type,
|
360
|
+
:d_value => d2
|
361
|
+
)
|
362
|
+
end
|
363
|
+
|
364
|
+
|
365
|
+
def nd1
|
366
|
+
@nd1 ||= GreekCalculations.misc_nd1(:d1 => d1)
|
367
|
+
end
|
368
|
+
|
369
|
+
end
|
370
|
+
end
|
371
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
require File.expand_path("../../spec_helper.rb", File.dirname(__FILE__))
|
2
|
+
|
3
|
+
describe "Math::GreekCalculations::delta" do
|
4
|
+
extend Math::GreekCalculations
|
5
|
+
include Math::GreekCalculations
|
6
|
+
|
7
|
+
it { delta(:option_type => :call, :rate_vs_expires => 1.0, :d1_normal_distribution => 1.0, :iv => 'any value').should === 1.0 }
|
8
|
+
it { delta(:option_type => :put, :rate_vs_expires => 1.0, :d1_normal_distribution => 1.0, :iv => 'any value').should === -1.0 }
|
9
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
require File.expand_path("../../spec_helper.rb", File.dirname(__FILE__))
|
2
|
+
|
3
|
+
describe "Math::GreekCalculations::gamma" do
|
4
|
+
extend Math::GreekCalculations
|
5
|
+
include Math::GreekCalculations
|
6
|
+
|
7
|
+
it { gamma(:stock_price => 1.0, :option_expires_pct_year_sqrt => 2.0, :iv => 3.0, :nd1 => 4.0, :rate_vs_expires => 5.0).round(2).should. === 3.33 }
|
8
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require File.expand_path("../../spec_helper.rb", File.dirname(__FILE__))
|
2
|
+
|
3
|
+
describe "Math::GreekCalculations::iv_option_price" do
|
4
|
+
include Math
|
5
|
+
include Math::GreekCalculations
|
6
|
+
include Math::GreekCalculationHelpers
|
7
|
+
|
8
|
+
let(:stock_price) { 10.00 }
|
9
|
+
let(:stock_dividend_rate_f) { 0.00 }
|
10
|
+
let(:option_type) { :call }
|
11
|
+
let(:option_expires_pct_year) { 1.00 }
|
12
|
+
let(:volatility_guess) { 0.50 }
|
13
|
+
|
14
|
+
context "exactly at the money" do
|
15
|
+
let(:option_strike) { 10.00 }
|
16
|
+
|
17
|
+
context "0% interest" do
|
18
|
+
let(:federal_reserve_interest_rate_f) { 0.00 }
|
19
|
+
let(:expected) { 1.9741254870839349 }
|
20
|
+
|
21
|
+
it { var_option_price().should === expected }
|
22
|
+
end
|
23
|
+
|
24
|
+
context "0.02% interest" do
|
25
|
+
let(:federal_reserve_interest_rate_f) { 0.0002 }
|
26
|
+
let(:expected) { 1.9749281489443273 }
|
27
|
+
|
28
|
+
it { var_option_price().should === expected }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context "out of the money" do
|
33
|
+
let(:option_strike) { 15.00 }
|
34
|
+
|
35
|
+
context "0% interest" do
|
36
|
+
let(:federal_reserve_interest_rate_f) { 0.00 }
|
37
|
+
let(:expected) { 0.7088126378267066 }
|
38
|
+
|
39
|
+
it { var_option_price().should === expected }
|
40
|
+
end
|
41
|
+
|
42
|
+
context "0.02% interest" do
|
43
|
+
let(:federal_reserve_interest_rate_f) { 0.0002 }
|
44
|
+
let(:expected) { 0.7092458172337008 }
|
45
|
+
|
46
|
+
it { var_option_price().should === expected }
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context "in of the money" do
|
51
|
+
let(:option_strike) { 5.00 }
|
52
|
+
|
53
|
+
context "0% interest" do
|
54
|
+
let(:federal_reserve_interest_rate_f) { 0.00 }
|
55
|
+
let(:expected) { 5.130693877506824 }
|
56
|
+
|
57
|
+
it { var_option_price().should === expected }
|
58
|
+
end
|
59
|
+
|
60
|
+
context "0.02% interest" do
|
61
|
+
let(:federal_reserve_interest_rate_f) { 0.0002 }
|
62
|
+
let(:expected) { 5.1315659170286185 }
|
63
|
+
|
64
|
+
it { var_option_price().should === expected }
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require File.expand_path("../../spec_helper.rb", File.dirname(__FILE__))
|
2
|
+
|
3
|
+
describe "Math::GreekCalculations::iv" do
|
4
|
+
extend Math::GreekCalculations
|
5
|
+
include Math::GreekCalculations
|
6
|
+
include Math::GreekCalculationHelpers
|
7
|
+
|
8
|
+
let(:stock_price) { 10.00 }
|
9
|
+
let(:stock_dividend_rate) { 0.0 }
|
10
|
+
let(:stock_dividend_rate_f) { 0.0 }
|
11
|
+
|
12
|
+
let(:option_price) { 1.00 }
|
13
|
+
let(:option_expires_in_days) { 364.0 }
|
14
|
+
let(:option_expires_pct_year) { 1.0 }
|
15
|
+
|
16
|
+
let(:federal_reserve_interest_rate) { 0.0 }
|
17
|
+
let(:federal_reserve_interest_rate_f) { 0.00 }
|
18
|
+
|
19
|
+
describe "call options" do
|
20
|
+
let(:option_type) { :call }
|
21
|
+
|
22
|
+
context "exactly at the money" do
|
23
|
+
let(:option_strike) { 10.00 }
|
24
|
+
it { var_iv().should === 0.25089263455361754 }
|
25
|
+
end
|
26
|
+
|
27
|
+
context "out of the money" do
|
28
|
+
let(:option_strike) { 15.00 }
|
29
|
+
it { var_iv().should === 0.5819996182323802 }
|
30
|
+
end
|
31
|
+
|
32
|
+
context "in the money" do
|
33
|
+
let(:option_strike) { 5.00 }
|
34
|
+
it { var_iv().should === nil }
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "put options" do
|
39
|
+
let(:option_type) { :put }
|
40
|
+
|
41
|
+
context "exactly at the money" do
|
42
|
+
let(:option_strike) { 10.00 }
|
43
|
+
it { var_iv().should === 0.25089263455361754 }
|
44
|
+
end
|
45
|
+
|
46
|
+
context "out of the money" do
|
47
|
+
let(:option_strike) { 15.00 }
|
48
|
+
it { var_iv().should === nil }
|
49
|
+
end
|
50
|
+
|
51
|
+
context "in the money" do
|
52
|
+
let(:option_strike) { 5.00 }
|
53
|
+
it { var_iv().should === 1.0245859277769118 }
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require File.expand_path("../../spec_helper.rb", File.dirname(__FILE__))
|
2
|
+
|
3
|
+
describe "Math::GreekCalculations::iv_vega" do
|
4
|
+
include Math
|
5
|
+
include Math::GreekCalculations
|
6
|
+
include Math::GreekCalculationHelpers
|
7
|
+
|
8
|
+
let(:stock_price) { 10.00 }
|
9
|
+
let(:stock_dividend_rate_f) { 0.00 }
|
10
|
+
let(:option_expires_pct_year) { 1.00 }
|
11
|
+
let(:volatility_guess) { 0.50 }
|
12
|
+
|
13
|
+
context "exactly at the money" do
|
14
|
+
let(:option_strike) { 10.00 }
|
15
|
+
|
16
|
+
context "0% interest" do
|
17
|
+
let(:federal_reserve_interest_rate_f) { 0.00 }
|
18
|
+
let(:expected) { 3.866681168028493 }
|
19
|
+
|
20
|
+
it { var_vega().should === expected }
|
21
|
+
end
|
22
|
+
|
23
|
+
context "0.02% interest" do
|
24
|
+
let(:federal_reserve_interest_rate_f) { 0.0002 }
|
25
|
+
let(:expected) { 3.866294209940902 }
|
26
|
+
|
27
|
+
it { var_vega().should === expected }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context "out of the money" do
|
32
|
+
let(:option_strike) { 15.00 }
|
33
|
+
|
34
|
+
context "0% interest" do
|
35
|
+
let(:federal_reserve_interest_rate_f) { 0.00 }
|
36
|
+
let(:expected) { 3.4086802947730774 }
|
37
|
+
|
38
|
+
it { var_vega().should === expected }
|
39
|
+
end
|
40
|
+
|
41
|
+
context "0.02% interest" do
|
42
|
+
let(:federal_reserve_interest_rate_f) { 0.0002 }
|
43
|
+
let(:expected) { 3.4094449205351056 }
|
44
|
+
|
45
|
+
it { var_vega().should === expected }
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context "in of the money" do
|
50
|
+
let(:option_strike) { 5.00 }
|
51
|
+
|
52
|
+
context "0% interest" do
|
53
|
+
let(:federal_reserve_interest_rate_f) { 0.00 }
|
54
|
+
let(:expected) { 1.045940982192684 }
|
55
|
+
|
56
|
+
it { var_vega().should === expected }
|
57
|
+
end
|
58
|
+
|
59
|
+
context "0.02% interest" do
|
60
|
+
let(:federal_reserve_interest_rate_f) { 0.0002 }
|
61
|
+
let(:expected) { 1.045256535627944 }
|
62
|
+
|
63
|
+
it { var_vega().should === expected }
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require File.expand_path("../../spec_helper.rb", File.dirname(__FILE__))
|
2
|
+
|
3
|
+
describe "Math::GreekCalculations::normal_distribution" do
|
4
|
+
extend Math::GreekCalculations
|
5
|
+
include Math::GreekCalculations
|
6
|
+
|
7
|
+
it "should take 0.000005s per calculation" do
|
8
|
+
test_speed(0.000005) { normal_distribution(0.0) }
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should calculate the normal_distribution" do
|
12
|
+
normal_distribution(-0.0).should === 0.5000000005248086
|
13
|
+
normal_distribution(0.038237059844021946).should === 0.5152507249371991
|
14
|
+
normal_distribution(0.038410221197121876).should === 0.5153197557441735
|
15
|
+
normal_distribution(0.05419795049563356).should === 0.5216113427954938
|
16
|
+
normal_distribution(0.08866836079942457).should === 0.5353273260368764
|
17
|
+
normal_distribution(0.22705303864277918).should === 0.5898087102891723
|
18
|
+
normal_distribution(0.23102722425730948).should === 0.5913531319833535
|
19
|
+
normal_distribution(0.24375225242810844).should === 0.5962886004762329
|
20
|
+
normal_distribution(0.24745839358343474).should === 0.5977232060736917
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
require File.expand_path("../../spec_helper.rb", File.dirname(__FILE__))
|
2
|
+
|
3
|
+
describe "Math::GreekCalculations::rho" do
|
4
|
+
extend Math::GreekCalculations
|
5
|
+
include Math::GreekCalculations
|
6
|
+
|
7
|
+
it { rho(:option_type => :call, :option_expires_pct_year => 1.0, :strike_vs_fed_vs_expires => 2.0, :d2_normal_distribution => 3.0, :iv => 'any value').should === 0.06 }
|
8
|
+
it { rho(:option_type => :put, :option_expires_pct_year => 1.0, :strike_vs_fed_vs_expires => 2.0, :d2_normal_distribution => 3.0, :iv => 'any value').should === -0.06 }
|
9
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
require File.expand_path("../../spec_helper.rb", File.dirname(__FILE__))
|
2
|
+
|
3
|
+
describe "Math::GreekCalculations::theta" do
|
4
|
+
extend Math::GreekCalculations
|
5
|
+
include Math::GreekCalculations
|
6
|
+
|
7
|
+
it { theta(:option_type => :call, :stock_dividend_rate_f => 1.0005, :federal_reserve_interest_rate_f => 2.0002, :option_expires_pct_year_sqrt => 1.0, :iv => 1.0, :strike_vs_fed_vs_expires => 3.0, :price_vs_rate_vs_expires => 4.0, :nd1 => 5.0, :d1_normal_distribution => 6.0, :d2_normal_distribution => 7.0).should === -0.0766909589041096 }
|
8
|
+
|
9
|
+
it { theta(:option_type => :put, :stock_dividend_rate_f => 1.0005, :federal_reserve_interest_rate_f => 2.0002, :option_expires_pct_year_sqrt => 1.0, :iv => 1.0, :strike_vs_fed_vs_expires => 3.0, :price_vs_rate_vs_expires => 4.0, :nd1 => 5.0, :d1_normal_distribution => 6.0, :d2_normal_distribution => 7.0).should === 0.021896438356164394 }
|
10
|
+
end
|