greeks 1.2 → 1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/greeks-1.1.gem +0 -0
- data/greeks.gemspec +1 -1
- data/lib/greeks/calculations/time_values.rb +12 -14
- data/lib/greeks.rb +24 -6
- data/spec/greeks/22days.calls.csv +1 -0
- data/spec/greeks/22days.puts.csv +1 -0
- data/spec/greeks/50days.calls.csv +1 -0
- data/spec/greeks/50days.puts.csv +1 -0
- data/spec/greeks/calculations/iv_option_price_spec.rb +0 -1
- data/spec/greeks/calculations/iv_spec.rb +0 -1
- data/spec/greeks/calculations/iv_vega_spec.rb +0 -1
- data/spec/greeks/calculations/time_values_spec.rb +0 -1
- data/spec/greeks/greeks_spec.rb +30 -104
- data/spec/helpers/greek_calculation_shorthand_helpers.rb +54 -0
- data/spec/spec_helper.rb +14 -54
- data/spec/support/calculate_greeks_hash.rb +39 -0
- metadata +15 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2ed185ec81ab234f6465a7a78a435ddfcd7055d6
|
|
4
|
+
data.tar.gz: 624f32c01e177d5cb626f081f5ed7068bc1d31bd
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3f0accecffdf8324a71297cc584b1d6fb53100c9a4f1cf9b48a52b0bf1c657e6cdce8d5a4ad12d82ca0ca0cd6af601ce833f33bf2b9c79a1db39a08a2e48e509
|
|
7
|
+
data.tar.gz: edafcc4521dbb21879e0ed7a575f61fb5616b818f03620d7054d47d5181383f09dbcfcb4d234c1d9347c034defa0dd84298f80350026f53328df534a3e5db32b
|
data/Gemfile.lock
CHANGED
data/greeks-1.1.gem
ADDED
|
Binary file
|
data/greeks.gemspec
CHANGED
|
@@ -2,7 +2,7 @@ module Math
|
|
|
2
2
|
module GreekCalculations
|
|
3
3
|
|
|
4
4
|
def nil_or_gte0(value)
|
|
5
|
-
value.nil? || value.to_f < 0 ? nil : value
|
|
5
|
+
value.nil? || value.to_f < 0.0 ? nil : value
|
|
6
6
|
end
|
|
7
7
|
|
|
8
8
|
|
|
@@ -15,14 +15,16 @@ module Math
|
|
|
15
15
|
def premium_value(opts)
|
|
16
16
|
opts.requires_fields(:option_type, :option_strike, :stock_price)
|
|
17
17
|
|
|
18
|
-
case opts[:option_type]
|
|
18
|
+
value = case opts[:option_type]
|
|
19
19
|
when :call
|
|
20
|
-
|
|
20
|
+
[opts[:stock_price] - opts[:option_strike], 0].max
|
|
21
21
|
when :put
|
|
22
|
-
|
|
22
|
+
[opts[:option_strike] - opts[:stock_price], 0].max
|
|
23
23
|
else
|
|
24
24
|
raise ArgumentError, "Invalid option_type = #{opts[:option_type]}"
|
|
25
25
|
end
|
|
26
|
+
|
|
27
|
+
nil_or_gte0(value)
|
|
26
28
|
end
|
|
27
29
|
|
|
28
30
|
|
|
@@ -34,10 +36,8 @@ module Math
|
|
|
34
36
|
# of $35 were trading for $7, the call would have a $5 intrinsic value ($40-$35) and a $2 time value ($7-$5).
|
|
35
37
|
# Time value will decay by expiration assuming the underlying security stays at the same price.
|
|
36
38
|
def time_value(opts)
|
|
37
|
-
opts.
|
|
38
|
-
|
|
39
|
-
return nil if opts[:option_price].nil?
|
|
40
|
-
return nil if opts[:option_price] < 0
|
|
39
|
+
return nil if opts[:option_price].nil? || opts[:option_price] < 0
|
|
40
|
+
return nil if opts[:premium_value].nil? || opts[:premium_value] < 0
|
|
41
41
|
|
|
42
42
|
nil_or_gte0(opts[:option_price] - opts[:premium_value])
|
|
43
43
|
end
|
|
@@ -48,11 +48,10 @@ module Math
|
|
|
48
48
|
# premium to develop an intuitive understanding of how much the market is "paying" for a dollar of risk.
|
|
49
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
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
|
-
|
|
51
|
+
def annualized_premium_value(opts)
|
|
54
52
|
return nil if opts[:option_price].nil?
|
|
55
53
|
return nil if opts[:option_price] < 0
|
|
54
|
+
opts.requires_fields(:option_price, :option_strike, :option_expires_pct_year)
|
|
56
55
|
|
|
57
56
|
nil_or_gte0(100 * Math.log(1 + opts[:option_price] / opts[:option_strike]) / opts[:option_expires_pct_year])
|
|
58
57
|
end
|
|
@@ -65,10 +64,9 @@ module Math
|
|
|
65
64
|
# six month call on that stock with a strike price of $35 has an intrinsic value of $5 and a total
|
|
66
65
|
# value of $7, the time value ($2) divided by the strike is ($2/$40) = 5%. Annualizing that time value
|
|
67
66
|
# to a one year horizon on a continuously compounded basis yields 9.76% (2 × ln(1 + 0.05)).
|
|
68
|
-
def annualized_time_value
|
|
67
|
+
def annualized_time_value(opts)
|
|
68
|
+
return nil if opts[:time_value].nil? || opts[:time_value] < 0
|
|
69
69
|
opts.requires_fields(:option_strike, :option_expires_pct_year, :time_value)
|
|
70
|
-
|
|
71
|
-
return nil if opts[:time_value].nil?
|
|
72
70
|
|
|
73
71
|
nil_or_gte0(100 * Math.log(1.0 + opts[:time_value] / opts[:option_strike]) / opts[:option_expires_pct_year])
|
|
74
72
|
end
|
data/lib/greeks.rb
CHANGED
|
@@ -34,6 +34,10 @@ module Math
|
|
|
34
34
|
attr_reader :price_vs_rate_vs_expires
|
|
35
35
|
attr_reader :strike_vs_fed_vs_expires
|
|
36
36
|
attr_reader :price_ratio_log_less_rates
|
|
37
|
+
|
|
38
|
+
# Optional fields
|
|
39
|
+
attr_reader :option_volume
|
|
40
|
+
attr_reader :option_open_interest
|
|
37
41
|
|
|
38
42
|
|
|
39
43
|
def initialize(opts)
|
|
@@ -50,6 +54,9 @@ module Math
|
|
|
50
54
|
@option_expires_pct_year = (option_expires_in_days + 1.0) / 365.0
|
|
51
55
|
@option_expires_pct_year_sqrt = Math.sqrt(option_expires_pct_year)
|
|
52
56
|
|
|
57
|
+
@option_volume = opts[:option_volume]
|
|
58
|
+
@option_open_interest = opts[:option_open_interest]
|
|
59
|
+
|
|
53
60
|
|
|
54
61
|
@price_vs_rate_vs_expires = GreekCalculations.misc_price_vs_rate_vs_expires(
|
|
55
62
|
:stock_price => stock_price,
|
|
@@ -281,7 +288,8 @@ module Math
|
|
|
281
288
|
|
|
282
289
|
|
|
283
290
|
def to_hash
|
|
284
|
-
hash
|
|
291
|
+
return @hash if @hash
|
|
292
|
+
@hash = {
|
|
285
293
|
:federal_reserve_interest_rate => federal_reserve_interest_rate,
|
|
286
294
|
:stock_dividend_rate => stock_dividend_rate,
|
|
287
295
|
:stock_price => stock_price,
|
|
@@ -289,13 +297,19 @@ module Math
|
|
|
289
297
|
:option_type => option_type,
|
|
290
298
|
:option_strike => option_strike,
|
|
291
299
|
:option_price => option_price,
|
|
300
|
+
:option_volume => option_volume,
|
|
301
|
+
:option_open_interest => option_open_interest,
|
|
302
|
+
:premium_value => premium_value,
|
|
303
|
+
:time_value => time_value,
|
|
304
|
+
:annualized_premium_value => annualized_premium_value,
|
|
305
|
+
:annualized_time_value => annualized_time_value,
|
|
292
306
|
:iv => (NilMath.new(iv) * 100.0).to_f, # iv * 100
|
|
293
307
|
:delta => (NilMath.new(delta) * stock_price / option_price).to_f, # delta * stock_price / option_price
|
|
294
308
|
:gamma => (NilMath.new(gamma) * stock_price / delta).to_f, # gamma * stock_price / delta
|
|
295
309
|
:vega => (NilMath.new(vega) * 100.0 * iv / option_price).to_f, # vega * iv * 100 / option_price
|
|
296
310
|
:rho => (NilMath.new(rho) * 100.0 / option_price).to_f, # rho * 100 / option_price
|
|
297
311
|
:theta => (NilMath.new(theta) * 100.0 / option_price).to_f, # theta * 100 / option_price
|
|
298
|
-
:
|
|
312
|
+
:delta_vs_theta => nil,
|
|
299
313
|
:break_even => (NilMath.new(break_even) * 100.0).to_f, # break_even * 100
|
|
300
314
|
}
|
|
301
315
|
|
|
@@ -305,14 +319,18 @@ module Math
|
|
|
305
319
|
# decay rate, the trend in the Delta/Theta column indicates which options give the most exposure
|
|
306
320
|
# to the movement of the underlying stock or index for a given decay rate of the option value.
|
|
307
321
|
# The highest numbers indicate the most bang for the buck for the least decay rate.
|
|
308
|
-
hash[:
|
|
322
|
+
@hash[:delta_vs_theta] = (NilMath.new(@hash[:delta]) / @hash[:theta]).to_f
|
|
309
323
|
|
|
310
324
|
# Iterate the generated columns and round the output
|
|
311
|
-
|
|
312
|
-
|
|
325
|
+
# Skip all the fields related to the input data: Federal, Stock, & Option
|
|
326
|
+
@hash.keys.reject do |key|
|
|
327
|
+
key = key.to_s
|
|
328
|
+
key.start_with?('federal_') || key.start_with?('stock_') || key.start_with?('option_')
|
|
329
|
+
end.each do |key|
|
|
330
|
+
@hash[key] &&= @hash[key].round(2)
|
|
313
331
|
end
|
|
314
332
|
|
|
315
|
-
hash
|
|
333
|
+
@hash
|
|
316
334
|
end
|
|
317
335
|
|
|
318
336
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
:stock_price,:stock_dividend_rate,:federal_reserve_interest_rate,:option_expires_in_days,:option_strike,:option_price,:option_volume,:option_open_interest,:iv,:delta,:gamma,:vega,:rho,:theta,:delta_vs_theta,:annualized_premium_value,:premium_value,:time_value,:annualized_time_value,:break_even
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
:stock_price,:stock_dividend_rate,:federal_reserve_interest_rate,:option_expires_in_days,:option_strike,:option_price,:option_volume,:option_open_interest,:iv,:delta,:gamma,:vega,:rho,:theta,:delta_vs_theta,:annualized_premium_value,:premium_value,:time_value,:annualized_time_value,:break_even
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
:stock_price,:stock_dividend_rate,:federal_reserve_interest_rate,:option_expires_in_days,:option_strike,:option_price,:option_volume,:option_open_interest,:iv,:delta,:gamma,:vega,:rho,:theta,:delta_vs_theta,:annualized_premium_value,:premium_value,:time_value,:annualized_time_value,:break_even
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
:stock_price,:stock_dividend_rate,:federal_reserve_interest_rate,:option_expires_in_days,:option_strike,:option_price,:option_volume,:option_open_interest,:iv,:delta,:gamma,:vega,:rho,:theta,:delta_vs_theta,:annualized_premium_value,:premium_value,:time_value,:annualized_time_value,:break_even
|
|
@@ -3,7 +3,6 @@ require File.expand_path("../../spec_helper.rb", File.dirname(__FILE__))
|
|
|
3
3
|
describe "Math::GreekCalculations::iv_option_price" do
|
|
4
4
|
include Math
|
|
5
5
|
include Math::GreekCalculations
|
|
6
|
-
include Math::GreekCalculationHelpers
|
|
7
6
|
|
|
8
7
|
let(:stock_price) { 10.00 }
|
|
9
8
|
let(:stock_dividend_rate_f) { 0.00 }
|
|
@@ -3,7 +3,6 @@ require File.expand_path("../../spec_helper.rb", File.dirname(__FILE__))
|
|
|
3
3
|
describe "Math::GreekCalculations::iv_vega" do
|
|
4
4
|
include Math
|
|
5
5
|
include Math::GreekCalculations
|
|
6
|
-
include Math::GreekCalculationHelpers
|
|
7
6
|
|
|
8
7
|
let(:stock_price) { 10.00 }
|
|
9
8
|
let(:stock_dividend_rate_f) { 0.00 }
|
|
@@ -3,7 +3,6 @@ require File.expand_path("../../spec_helper.rb", File.dirname(__FILE__))
|
|
|
3
3
|
describe "Math::GreekCalculations::misc_price_ratio_log_less_rates" do
|
|
4
4
|
include Math
|
|
5
5
|
include Math::GreekCalculations
|
|
6
|
-
include Math::GreekCalculationHelpers
|
|
7
6
|
|
|
8
7
|
let(:stock_price) { 10.00 }
|
|
9
8
|
let(:stock_dividend_rate_f) { 0.00 }
|
data/spec/greeks/greeks_spec.rb
CHANGED
|
@@ -1,116 +1,42 @@
|
|
|
1
1
|
require File.expand_path("../spec_helper.rb", File.dirname(__FILE__))
|
|
2
2
|
|
|
3
3
|
describe Math::Greeks::Calculator do
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
let(:date) { '2013-06-21' }
|
|
13
|
-
let(:days) { 35.0 }
|
|
14
|
-
|
|
15
|
-
let(:call) do
|
|
16
|
-
{
|
|
17
|
-
:strike => 4.50,
|
|
18
|
-
:bid => 0.16,
|
|
19
|
-
:iv => 61.92,
|
|
20
|
-
:delta => 8.59,
|
|
21
|
-
:gamma => 5.57,
|
|
22
|
-
:vega => 1.81,
|
|
23
|
-
:rho => 0.75,
|
|
24
|
-
:theta => -2.51,
|
|
25
|
-
:break_even => 21.38,
|
|
26
|
-
}
|
|
27
|
-
end
|
|
4
|
+
# Helper method to iterate the sample data
|
|
5
|
+
def compare_csv(days, option_type)
|
|
6
|
+
table = CSV.table(File.join(File.dirname(__FILE__), "#{days}days.#{option_type}s.csv"))
|
|
7
|
+
|
|
8
|
+
table.each do |row|
|
|
9
|
+
# Convert to a hash
|
|
10
|
+
row = row.to_hash
|
|
28
11
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
:
|
|
40
|
-
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
let(:base_opts) do
|
|
44
|
-
{
|
|
45
|
-
:stock_price => 4.07,
|
|
46
|
-
:stock_dividend_rate => 0.00,
|
|
47
|
-
:option_expires_in_days => 35.0,
|
|
48
|
-
:federal_reserve_interest_rate => 0.01,
|
|
49
|
-
:option_type => nil,
|
|
50
|
-
:option_price => nil,
|
|
51
|
-
:option_strike => nil,
|
|
52
|
-
}
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
context "call option" do
|
|
56
|
-
let(:opts) do
|
|
57
|
-
base_opts.merge(
|
|
58
|
-
:option_type => :call,
|
|
59
|
-
:option_price => call[:bid],
|
|
60
|
-
:option_strike => call[:strike],
|
|
61
|
-
)
|
|
12
|
+
# Strip empty/nil values
|
|
13
|
+
row.each do |k,v|
|
|
14
|
+
if v.to_s === "nil" || v.to_s.strip.empty?
|
|
15
|
+
row[k] = nil
|
|
16
|
+
else
|
|
17
|
+
row[k] = row[k].to_f
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Calculate the options
|
|
22
|
+
row.merge!(:option_type => option_type)
|
|
23
|
+
Math::Greeks::Calculator.new(row).should be_a_greeks_hash row
|
|
62
24
|
end
|
|
25
|
+
end
|
|
63
26
|
|
|
64
|
-
|
|
27
|
+
it "compute call options @ 22 days" do
|
|
28
|
+
compare_csv(22, :call)
|
|
29
|
+
end
|
|
65
30
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
it { calc.option_type.should === opts[:option_type] }
|
|
69
|
-
it { calc.option_price.should === opts[:option_price] }
|
|
70
|
-
it { calc.option_strike.should === opts[:option_strike] }
|
|
71
|
-
it { calc.option_expires_in_days.should === opts[:option_expires_in_days] }
|
|
72
|
-
it { calc.federal_reserve_interest_rate.should === opts[:federal_reserve_interest_rate] }
|
|
73
|
-
|
|
74
|
-
it { calc.to_hash[:iv].should === call[:iv] }
|
|
75
|
-
it { calc.to_hash[:delta].should === call[:delta] }
|
|
76
|
-
it { calc.to_hash[:gamma].should === call[:gamma] }
|
|
77
|
-
it { calc.to_hash[:vega].should === call[:vega] }
|
|
78
|
-
it { calc.to_hash[:theta].should === call[:theta] }
|
|
79
|
-
it { calc.to_hash[:rho].should === call[:rho] }
|
|
80
|
-
it { calc.to_hash[:break_even].round(2).should === call[:break_even] }
|
|
31
|
+
it "compute put options @ 22 days" do
|
|
32
|
+
compare_csv(22, :put)
|
|
81
33
|
end
|
|
82
|
-
|
|
83
|
-
context "put option" do
|
|
84
|
-
let(:opts) do
|
|
85
|
-
base_opts.merge(
|
|
86
|
-
:option_type => :put,
|
|
87
|
-
:option_price => put[:bid],
|
|
88
|
-
:option_strike => put[:strike],
|
|
89
|
-
)
|
|
90
|
-
end
|
|
91
34
|
|
|
92
|
-
|
|
35
|
+
it "compute call options @ 50 days" do
|
|
36
|
+
compare_csv(50, :call)
|
|
37
|
+
end
|
|
93
38
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
it { calc.option_type.should === opts[:option_type] }
|
|
97
|
-
it { calc.option_price.should === opts[:option_price] }
|
|
98
|
-
it { calc.option_strike.should === opts[:option_strike] }
|
|
99
|
-
it { calc.option_expires_in_days.should === opts[:option_expires_in_days] }
|
|
100
|
-
it { calc.federal_reserve_interest_rate.should === opts[:federal_reserve_interest_rate] }
|
|
101
|
-
|
|
102
|
-
it { calc.to_hash[:iv].should === put[:iv] }
|
|
103
|
-
it { calc.to_hash[:delta].should === put[:delta] }
|
|
104
|
-
it { calc.to_hash[:gamma].should === put[:gamma] }
|
|
105
|
-
it { calc.to_hash[:vega].should === put[:vega] }
|
|
106
|
-
it { calc.to_hash[:theta].should === put[:theta] }
|
|
107
|
-
it { calc.to_hash[:rho].should === put[:rho] }
|
|
108
|
-
it { calc.to_hash[:break_even].round(2).should === put[:break_even] }
|
|
39
|
+
it "compute put options @ 50 days" do
|
|
40
|
+
compare_csv(50, :put)
|
|
109
41
|
end
|
|
110
|
-
|
|
111
|
-
it {
|
|
112
|
-
calculator = Math::Greeks::Calculator.new(:stock_price=>1558.86, :stock_dividend_rate=>0.0, :federal_reserve_interest_rate=>0.0, :option_type=>:call, :option_price=>751.50, :option_strike=>800.00, :option_expires_in_days=>2)
|
|
113
|
-
calculator.iv.should be_nil
|
|
114
|
-
calculator.to_hash[:iv].should be_nil
|
|
115
|
-
}
|
|
116
42
|
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
|
|
2
|
+
module Math
|
|
3
|
+
module GreekCalculationShorthandHelpers
|
|
4
|
+
include Math
|
|
5
|
+
include Math::GreekCalculations
|
|
6
|
+
|
|
7
|
+
def var_price_ratio_log_less_rates
|
|
8
|
+
misc_price_ratio_log_less_rates(
|
|
9
|
+
:stock_price => stock_price,
|
|
10
|
+
:option_strike => option_strike,
|
|
11
|
+
:option_expires_pct_year => option_expires_pct_year,
|
|
12
|
+
:federal_reserve_interest_rate_f => federal_reserve_interest_rate_f,
|
|
13
|
+
:stock_dividend_rate_f => stock_dividend_rate_f
|
|
14
|
+
)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def var_price_vs_rate_vs_expires
|
|
18
|
+
misc_price_vs_rate_vs_expires(
|
|
19
|
+
:stock_price => stock_price,
|
|
20
|
+
:option_expires_pct_year => option_expires_pct_year,
|
|
21
|
+
:stock_dividend_rate_f => stock_dividend_rate_f
|
|
22
|
+
)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def var_vega
|
|
26
|
+
iv_vega(stock_price, option_strike, option_expires_pct_year, volatility_guess, federal_reserve_interest_rate_f, stock_dividend_rate_f, var_price_ratio_log_less_rates, var_price_vs_rate_vs_expires)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def var_vega
|
|
30
|
+
iv_vega(stock_price, option_strike, option_expires_pct_year, Math::sqrt(option_expires_pct_year), volatility_guess, federal_reserve_interest_rate_f, stock_dividend_rate_f, var_price_ratio_log_less_rates, var_price_vs_rate_vs_expires)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def var_option_price
|
|
34
|
+
iv_option_price(stock_price, option_strike, option_expires_pct_year, Math::sqrt(option_expires_pct_year), volatility_guess, federal_reserve_interest_rate_f, stock_dividend_rate_f, option_type, var_price_ratio_log_less_rates, var_price_vs_rate_vs_expires, misc_strike_vs_fed_vs_expires(:option_strike => option_strike, :option_expires_pct_year => option_expires_pct_year, :federal_reserve_interest_rate_f => federal_reserve_interest_rate_f))
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def var_iv
|
|
38
|
+
iv(
|
|
39
|
+
:stock_price => stock_price,
|
|
40
|
+
:option_strike => option_strike,
|
|
41
|
+
:option_expires_pct_year => option_expires_pct_year,
|
|
42
|
+
:option_expires_pct_year_sqrt => Math::sqrt(option_expires_pct_year),
|
|
43
|
+
:federal_reserve_interest_rate_f => federal_reserve_interest_rate_f,
|
|
44
|
+
:stock_dividend_rate_f => stock_dividend_rate_f,
|
|
45
|
+
:option_type => option_type,
|
|
46
|
+
:option_price => option_price,
|
|
47
|
+
:rate_vs_expires => misc_rate_vs_expires(:option_expires_pct_year => option_expires_pct_year, :stock_dividend_rate_f => stock_dividend_rate_f),
|
|
48
|
+
:price_vs_rate_vs_expires => var_price_vs_rate_vs_expires,
|
|
49
|
+
:strike_vs_fed_vs_expires => misc_strike_vs_fed_vs_expires(:option_strike => option_strike, :option_expires_pct_year => option_expires_pct_year, :federal_reserve_interest_rate_f => federal_reserve_interest_rate_f),
|
|
50
|
+
:price_ratio_log_less_rates => var_price_ratio_log_less_rates
|
|
51
|
+
)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
data/spec/spec_helper.rb
CHANGED
|
@@ -2,15 +2,29 @@ require 'rubygems'
|
|
|
2
2
|
require 'rspec'
|
|
3
3
|
require 'rspec-expectations'
|
|
4
4
|
require 'benchmark'
|
|
5
|
+
require 'require_all'
|
|
6
|
+
require 'csv'
|
|
5
7
|
|
|
6
8
|
$:.push File.expand_path("../lib", File.dirname(__FILE__))
|
|
7
9
|
require 'greeks'
|
|
8
10
|
|
|
9
11
|
$spec_root = File.dirname(__FILE__)
|
|
10
12
|
|
|
13
|
+
require_all File.join($spec_root, 'support')
|
|
14
|
+
require_all File.join($spec_root, 'helpers')
|
|
15
|
+
|
|
16
|
+
|
|
11
17
|
RSpec.configure do |config|
|
|
18
|
+
config.include Math::GreekCalculationShorthandHelpers
|
|
19
|
+
|
|
12
20
|
old_verbose, $VERBOSE = $VERBOSE, nil
|
|
13
21
|
|
|
22
|
+
def verbose_puts(s)
|
|
23
|
+
return unless $VERBOSE
|
|
24
|
+
file = File.basename(caller(1).first)
|
|
25
|
+
super("puts() from #{file}: #{s}")
|
|
26
|
+
end
|
|
27
|
+
|
|
14
28
|
def puts(s)
|
|
15
29
|
file = File.basename(caller(1).first)
|
|
16
30
|
super("puts() from #{file}: #{s}")
|
|
@@ -32,57 +46,3 @@ RSpec.configure do |config|
|
|
|
32
46
|
@result
|
|
33
47
|
end
|
|
34
48
|
end
|
|
35
|
-
|
|
36
|
-
module Math
|
|
37
|
-
module GreekCalculationHelpers
|
|
38
|
-
include Math
|
|
39
|
-
include Math::GreekCalculations
|
|
40
|
-
|
|
41
|
-
def var_price_ratio_log_less_rates
|
|
42
|
-
misc_price_ratio_log_less_rates(
|
|
43
|
-
:stock_price => stock_price,
|
|
44
|
-
:option_strike => option_strike,
|
|
45
|
-
:option_expires_pct_year => option_expires_pct_year,
|
|
46
|
-
:federal_reserve_interest_rate_f => federal_reserve_interest_rate_f,
|
|
47
|
-
:stock_dividend_rate_f => stock_dividend_rate_f
|
|
48
|
-
)
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
def var_price_vs_rate_vs_expires
|
|
52
|
-
misc_price_vs_rate_vs_expires(
|
|
53
|
-
:stock_price => stock_price,
|
|
54
|
-
:option_expires_pct_year => option_expires_pct_year,
|
|
55
|
-
:stock_dividend_rate_f => stock_dividend_rate_f
|
|
56
|
-
)
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
def var_vega
|
|
60
|
-
iv_vega(stock_price, option_strike, option_expires_pct_year, volatility_guess, federal_reserve_interest_rate_f, stock_dividend_rate_f, var_price_ratio_log_less_rates, var_price_vs_rate_vs_expires)
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
def var_vega
|
|
64
|
-
iv_vega(stock_price, option_strike, option_expires_pct_year, Math::sqrt(option_expires_pct_year), volatility_guess, federal_reserve_interest_rate_f, stock_dividend_rate_f, var_price_ratio_log_less_rates, var_price_vs_rate_vs_expires)
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
def var_option_price
|
|
68
|
-
iv_option_price(stock_price, option_strike, option_expires_pct_year, Math::sqrt(option_expires_pct_year), volatility_guess, federal_reserve_interest_rate_f, stock_dividend_rate_f, option_type, var_price_ratio_log_less_rates, var_price_vs_rate_vs_expires, misc_strike_vs_fed_vs_expires(:option_strike => option_strike, :option_expires_pct_year => option_expires_pct_year, :federal_reserve_interest_rate_f => federal_reserve_interest_rate_f))
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
def var_iv
|
|
72
|
-
iv(
|
|
73
|
-
:stock_price => stock_price,
|
|
74
|
-
:option_strike => option_strike,
|
|
75
|
-
:option_expires_pct_year => option_expires_pct_year,
|
|
76
|
-
:option_expires_pct_year_sqrt => Math::sqrt(option_expires_pct_year),
|
|
77
|
-
:federal_reserve_interest_rate_f => federal_reserve_interest_rate_f,
|
|
78
|
-
:stock_dividend_rate_f => stock_dividend_rate_f,
|
|
79
|
-
:option_type => option_type,
|
|
80
|
-
:option_price => option_price,
|
|
81
|
-
:rate_vs_expires => misc_rate_vs_expires(:option_expires_pct_year => option_expires_pct_year, :stock_dividend_rate_f => stock_dividend_rate_f),
|
|
82
|
-
:price_vs_rate_vs_expires => var_price_vs_rate_vs_expires,
|
|
83
|
-
:strike_vs_fed_vs_expires => misc_strike_vs_fed_vs_expires(:option_strike => option_strike, :option_expires_pct_year => option_expires_pct_year, :federal_reserve_interest_rate_f => federal_reserve_interest_rate_f),
|
|
84
|
-
:price_ratio_log_less_rates => var_price_ratio_log_less_rates
|
|
85
|
-
)
|
|
86
|
-
end
|
|
87
|
-
end
|
|
88
|
-
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
require 'rspec'
|
|
2
|
+
require 'rspec-expectations'
|
|
3
|
+
|
|
4
|
+
RSpec::Matchers.define :be_a_greeks_hash do |expected|
|
|
5
|
+
match do |actual|
|
|
6
|
+
hash = actual.to_hash
|
|
7
|
+
hash.should_not be_nil
|
|
8
|
+
hash.should_not be_empty
|
|
9
|
+
|
|
10
|
+
keys = [hash.keys, expected.keys].flatten.uniq.sort
|
|
11
|
+
verbose_puts "Keys: #{keys.inspect}"
|
|
12
|
+
keys.each do |key|
|
|
13
|
+
verbose_puts "[#{"%30s" % key}] Hash: #{hash[key].inspect} vs Actual: #{expected[key].inspect}"
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Delete all the values that match
|
|
17
|
+
# This will leave only the values that differ
|
|
18
|
+
expected.keys.dup.each do |key|
|
|
19
|
+
if hash[key] == expected[key]
|
|
20
|
+
expected.delete(key)
|
|
21
|
+
next
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
if hash[key].class == expected[key].class && !hash[key].nil? && !hash[key].is_a?(Symbol) && hash[key].round(1) == expected[key].round(1)
|
|
25
|
+
expected.delete(key)
|
|
26
|
+
next
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
expected[key] = "#{expected.delete(key).inspect}(e) vs #{hash[key].inspect}(a)"
|
|
30
|
+
end
|
|
31
|
+
verbose_puts "Hash: #{hash}"
|
|
32
|
+
verbose_puts "Expected: #{expected}"
|
|
33
|
+
expected.should be_empty
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
failure_message_for_should do |actual|
|
|
37
|
+
"expected that #{actual.to_hash} would match values of #{expected}"
|
|
38
|
+
end
|
|
39
|
+
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: greeks
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: '1.
|
|
4
|
+
version: '1.3'
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Glenn Nagel
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2013-05-
|
|
11
|
+
date: 2013-05-31 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: require_all
|
|
@@ -77,6 +77,7 @@ files:
|
|
|
77
77
|
- Gemfile
|
|
78
78
|
- Gemfile.lock
|
|
79
79
|
- README.md
|
|
80
|
+
- greeks-1.1.gem
|
|
80
81
|
- greeks.gemspec
|
|
81
82
|
- lib/greeks.rb
|
|
82
83
|
- lib/greeks/calculations/delta.rb
|
|
@@ -87,6 +88,10 @@ files:
|
|
|
87
88
|
- lib/greeks/calculations/theta.rb
|
|
88
89
|
- lib/greeks/calculations/time_values.rb
|
|
89
90
|
- lib/greeks/calculations/vega.rb
|
|
91
|
+
- spec/greeks/22days.calls.csv
|
|
92
|
+
- spec/greeks/22days.puts.csv
|
|
93
|
+
- spec/greeks/50days.calls.csv
|
|
94
|
+
- spec/greeks/50days.puts.csv
|
|
90
95
|
- spec/greeks/calculations/delta_spec.rb
|
|
91
96
|
- spec/greeks/calculations/gamma_spec.rb
|
|
92
97
|
- spec/greeks/calculations/iv_option_price_spec.rb
|
|
@@ -98,7 +103,9 @@ files:
|
|
|
98
103
|
- spec/greeks/calculations/time_values_spec.rb
|
|
99
104
|
- spec/greeks/calculations/vega_spec.rb
|
|
100
105
|
- spec/greeks/greeks_spec.rb
|
|
106
|
+
- spec/helpers/greek_calculation_shorthand_helpers.rb
|
|
101
107
|
- spec/spec_helper.rb
|
|
108
|
+
- spec/support/calculate_greeks_hash.rb
|
|
102
109
|
homepage: https://github.com/gnagel/greeks
|
|
103
110
|
licenses:
|
|
104
111
|
- MIT
|
|
@@ -126,6 +133,10 @@ specification_version: 4
|
|
|
126
133
|
summary: Calculate greeks for options trading (Implied Volatility, Delta, Gamma, Vega,
|
|
127
134
|
Rho, and Theta)
|
|
128
135
|
test_files:
|
|
136
|
+
- spec/greeks/22days.calls.csv
|
|
137
|
+
- spec/greeks/22days.puts.csv
|
|
138
|
+
- spec/greeks/50days.calls.csv
|
|
139
|
+
- spec/greeks/50days.puts.csv
|
|
129
140
|
- spec/greeks/calculations/delta_spec.rb
|
|
130
141
|
- spec/greeks/calculations/gamma_spec.rb
|
|
131
142
|
- spec/greeks/calculations/iv_option_price_spec.rb
|
|
@@ -137,4 +148,6 @@ test_files:
|
|
|
137
148
|
- spec/greeks/calculations/time_values_spec.rb
|
|
138
149
|
- spec/greeks/calculations/vega_spec.rb
|
|
139
150
|
- spec/greeks/greeks_spec.rb
|
|
151
|
+
- spec/helpers/greek_calculation_shorthand_helpers.rb
|
|
140
152
|
- spec/spec_helper.rb
|
|
153
|
+
- spec/support/calculate_greeks_hash.rb
|