options_library 1.0.0 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/Manifest CHANGED
@@ -1,5 +1,6 @@
1
+ Manifest
2
+ README.md
1
3
  Rakefile
2
4
  lib/options_library.rb
3
5
  lib/options_library/option_calculator.rb
4
6
  options_library.gemspec
5
- Manifest
data/README.md ADDED
@@ -0,0 +1,57 @@
1
+ Initial Author
2
+ --------------
3
+ Dan Tylenda-Emmons
4
+ Twitter: @CoderTrader
5
+ Email: jrubyist@gmail.com
6
+
7
+ Options Library
8
+ ===============
9
+
10
+ A pure Ruby implementation of the classic Black-Scholes option model for pricing Calls or Puts.
11
+
12
+ Goals
13
+ -------
14
+
15
+ * Provide the Open Source Ruby, JRuby and StockTwits communities with a publicly available model for computing option prices.
16
+ * Allow users of the library to compute price and greeks: delta, gamma, theta, vega and rho.
17
+ * To aid others in the understanding of how price and sensitivities to other factors are computed on a theoretical basis.
18
+ * To allo users of the library to extend or contribute back to the project so that it may be improved upon.
19
+
20
+
21
+ Installation
22
+ -----------
23
+
24
+ gem install options_library
25
+
26
+
27
+ Usage
28
+ -----
29
+
30
+ require 'rubygems'
31
+ require 'options_library'
32
+
33
+ # Option::Calculator.price_call( underlying, strike, time, interest, sigma, dividend )
34
+ call_price = Option::Calculator.price_call( 94.5, 90.5, 0.015, 0.01, 0.4875, 0.0 )
35
+
36
+ Testing
37
+ -------
38
+
39
+ To run the tests:
40
+
41
+ $ rake
42
+
43
+ To add tests see the `Commands` section earlier in this
44
+ README.
45
+
46
+
47
+ Contributing
48
+ ------------
49
+
50
+ 1. Fork it.
51
+ 2. Create a branch (`git checkout -b my_options_library`)
52
+ 3. Commit your changes (`git commit -am "Added Hull-White Model"`)
53
+ 4. Push to the branch (`git push origin my_options_library`)
54
+ 5. Create an [Issue][1] with a link to your branch
55
+ 6. Enjoy a fresh cup of coffee and wait
56
+
57
+ [1]: http://github.com/github/markup/issues
data/Rakefile CHANGED
@@ -2,7 +2,7 @@ require 'rubygems'
2
2
  require 'rake'
3
3
  require 'echoe'
4
4
 
5
- Echoe.new('options_library', '1.0.0') do |p|
5
+ Echoe.new('options_library', '1.0.2') do |p|
6
6
  p.description = 'A gem used to calc the price of an option.'
7
7
  p.url = 'http://github.com/codertrader/options_library'
8
8
  p.author = 'Dan Tylenda-Emmons'
@@ -5,121 +5,126 @@
5
5
  module Option
6
6
  class Calculator
7
7
  class << self
8
+ # used for finding implied vol based on a market (target) price
9
+ LOW_VOL, HIGH_VOL, VOL_TOLERANCE = 0.0, 5.0, 0.0001
10
+
11
+ # used for min/max normal distribution
12
+ MIN_Z_SCORE, MAX_Z_SCORE = -8.0, +8.0
8
13
 
9
- include Math
14
+ include Math
10
15
 
11
- # computes the call price sensitivity to a change in underlying price
12
- def delta_call( underlying, strike, time, interest, sigma, dividend )
13
- norm_sdist( d_one( underlying, strike, time, interest, sigma, dividend ) )
14
- end
16
+ # computes the call price sensitivity to a change in underlying price
17
+ def delta_call( underlying, strike, time, interest, sigma, dividend )
18
+ norm_sdist( d_one( underlying, strike, time, interest, sigma, dividend ) )
19
+ end
15
20
 
16
- # computes the put price sensitivity to a change in underlying price
17
- def delta_put( underlying, strike, time, interest, sigma, dividend )
18
- call_delta( underlying, strike, time, interest, sigma, dividend ) - 1
19
- end
21
+ # computes the put price sensitivity to a change in underlying price
22
+ def delta_put( underlying, strike, time, interest, sigma, dividend )
23
+ delta_call( underlying, strike, time, interest, sigma, dividend ) - 1
24
+ end
20
25
 
21
- # computes the option price sensitivity to a change in delta
22
- def gamma( underlying, strike, time, interest, sigma, dividend )
23
- phi( d_one( underlying, strike, time, interest, sigma, dividend ) ) / ( underlying * sigma * sqrt(time) )
24
- end
26
+ # computes the option price sensitivity to a change in delta
27
+ def gamma( underlying, strike, time, interest, sigma, dividend )
28
+ phi( d_one( underlying, strike, time, interest, sigma, dividend ) ) / ( underlying * sigma * sqrt(time) )
29
+ end
25
30
 
26
- # computes the option price sensitivity to a change in volatility
27
- def vega( underlying, strike, time, interest, sigma, dividend )
28
- 0.01 * underlying * sqrt(time) * phi(d_one(underlying, strike, time, interest, sigma, dividend))
29
- end
31
+ # computes the option price sensitivity to a change in volatility
32
+ def vega( underlying, strike, time, interest, sigma, dividend )
33
+ 0.01 * underlying * sqrt(time) * phi(d_one(underlying, strike, time, interest, sigma, dividend))
34
+ end
30
35
 
31
- # computes the fair value of the call based on the knowns and assumed volatility (sigma)
32
- def price_call( underlying, strike, time, interest, sigma, dividend )
33
- d1 = d_one( underlying, strike, time, interest, sigma, dividend )
34
- discounted_underlying = exp(-1.0 * dividend * time) * underlying
35
- probability_weighted_value_of_being_exercised = discounted_underlying * norm_sdist( d1 )
36
+ # computes the fair value of the call based on the knowns and assumed volatility (sigma)
37
+ def price_call( underlying, strike, time, interest, sigma, dividend )
38
+ d1 = d_one( underlying, strike, time, interest, sigma, dividend )
39
+ discounted_underlying = exp(-1.0 * dividend * time) * underlying
40
+ probability_weighted_value_of_being_exercised = discounted_underlying * norm_sdist( d1 )
36
41
 
37
- d2 = d1 - ( sigma * sqrt(time) )
38
- discounted_strike = exp(-1.0 * interest * time) * strike
39
- probability_weighted_value_of_discounted_strike = discounted_strike * norm_sdist( d2 )
42
+ d2 = d1 - ( sigma * sqrt(time) )
43
+ discounted_strike = exp(-1.0 * interest * time) * strike
44
+ probability_weighted_value_of_discounted_strike = discounted_strike * norm_sdist( d2 )
40
45
 
41
- expected_value = probability_weighted_value_of_being_exercised - probability_weighted_value_of_discounted_strike
42
- end
46
+ expected_value = probability_weighted_value_of_being_exercised - probability_weighted_value_of_discounted_strike
47
+ end
43
48
 
44
- # computes the fair value of the put based on the knowns and assumed volatility (sigma)
45
- def price_put( underlying, strike, time, interest, sigma, dividend )
46
- d2 = d_two( underlying, strike, time, interest, sigma, dividend )
47
- discounted_strike = strike * exp(-1.0 * interest * time)
48
- probabiltity_weighted_value_of_discounted_strike = discounted_strike * norm_sdist( -1.0 * d2 )
49
+ # computes the fair value of the put based on the knowns and assumed volatility (sigma)
50
+ def price_put( underlying, strike, time, interest, sigma, dividend )
51
+ d2 = d_two( underlying, strike, time, interest, sigma, dividend )
52
+ discounted_strike = strike * exp(-1.0 * interest * time)
53
+ probabiltity_weighted_value_of_discounted_strike = discounted_strike * norm_sdist( -1.0 * d2 )
49
54
 
50
- d1 = d2 + ( sigma * sqrt(time) )
51
- discounted_underlying = underlying * exp(-1.0 * dividend * time)
52
- probability_weighted_value_of_being_exercised = discounted_underlying * norm_sdist( -1.0 * d1 )
55
+ d1 = d2 + ( sigma * sqrt(time) )
56
+ discounted_underlying = underlying * exp(-1.0 * dividend * time)
57
+ probability_weighted_value_of_being_exercised = discounted_underlying * norm_sdist( -1.0 * d1 )
53
58
 
54
- expected_value = probabiltity_weighted_value_of_discounted_strike - probability_weighted_value_of_being_exercised
55
- end
59
+ expected_value = probabiltity_weighted_value_of_discounted_strike - probability_weighted_value_of_being_exercised
60
+ end
56
61
 
57
- # finds the implied volatility based on the target_price passed in.
58
- def implied_vol_call( underlying, strike, time, interest, target_price, dividend )
59
- low, high = 0, 5
62
+ # finds the implied volatility based on the target_price passed in.
63
+ def implied_vol_call( underlying, strike, time, interest, target_price, dividend )
64
+ low, high = LOW_VOL, HIGH_VOL
60
65
 
61
- while( high - low > 0.0001 )
62
- if( call_option( underlying, strike, time, interest, (high+low)/2.0, dividend ) > target_price )
63
- high = (high + low) / 2.0
64
- else
65
- low = (high + low) / 2.0
66
- end
67
- end
66
+ while( high - low > VOL_TOLERANCE )
67
+ if( price_call( underlying, strike, time, interest, (high+low)/2.0, dividend ) > target_price )
68
+ high = (high + low) / 2.0
69
+ else
70
+ low = (high + low) / 2.0
71
+ end
72
+ end
68
73
 
69
- (high + low) / 2.0
74
+ (high + low) / 2.0
70
75
  end
71
76
 
72
- # finds the implied volatility based on the target_price passed in.
73
- def implied_vol_put( underlying, strike, time, interest, target_price, dividend )
74
- low, high = 0, 5
77
+ # finds the implied volatility based on the target_price passed in.
78
+ def implied_vol_put( underlying, strike, time, interest, target_price, dividend )
79
+ low, high = LOW_VOL, HIGH_VOL
75
80
 
76
- while( high - low > 0.0001 )
77
- if( put_option( underlying, strike, time, interest, (high+low)/2.0, dividend ) > target_price )
78
- high = (high + low) / 2.0
79
- else
80
- low = (high + low) / 2.0
81
- end
82
- end
81
+ while( high - low > VOL_TOLERANCE )
82
+ if( price_put( underlying, strike, time, interest, (high+low)/2.0, dividend ) > target_price )
83
+ high = (high + low) / 2.0
84
+ else
85
+ low = (high + low) / 2.0
86
+ end
87
+ end
83
88
 
84
- (high + low) / 2.0
85
- end
89
+ (high + low) / 2.0
90
+ end
86
91
 
87
- # probability of being exercised at maturity (must be greater than d2 by (sigma*sqrt(time)) if exercised)
88
- def d_one( underlying, strike, time, interest, sigma, dividend )
89
- numerator = ( log(underlying / strike) + (interest - dividend + 0.5 * sigma ** 2.0 ) * time)
90
- denominator = ( sigma * sqrt(time) )
91
- numerator / denominator
92
- end
92
+ # probability of being exercised at maturity (must be greater than d2 by (sigma*sqrt(time)) if exercised)
93
+ def d_one( underlying, strike, time, interest, sigma, dividend )
94
+ numerator = ( log(underlying / strike) + (interest - dividend + 0.5 * sigma ** 2.0 ) * time)
95
+ denominator = ( sigma * sqrt(time) )
96
+ numerator / denominator
97
+ end
93
98
 
94
- # probability of underlying reaching the strike price (must be smaller than d1 by (sigma*sqrt(time)) if exercised.
95
- def d_two( underlying, strike, time, interest, sigma, dividend )
96
- d_one( underlying, strike, time, interest, sigma, dividend ) - ( sigma * sqrt(time) )
97
- end
99
+ # probability of underlying reaching the strike price (must be smaller than d1 by (sigma*sqrt(time)) if exercised.
100
+ def d_two( underlying, strike, time, interest, sigma, dividend )
101
+ d_one( underlying, strike, time, interest, sigma, dividend ) - ( sigma * sqrt(time) )
102
+ end
98
103
 
99
- # Normal Standard Distribution
100
- # using Taylor's approximation
101
- def norm_sdist( z )
102
- return 0.0 if z < -8.0
103
- return 1.0 if z > +8.0
104
+ # Normal Standard Distribution
105
+ # using Taylor's approximation
106
+ def norm_sdist( z )
107
+ return 0.0 if z < MIN_Z_SCORE
108
+ return 1.0 if z > MAX_Z_SCORE
104
109
 
105
- i, sum, term = 3.0, 0.0, z
110
+ i, sum, term = 3.0, 0.0, z
106
111
 
107
- while( sum + term != sum )
108
- sum = sum + term
109
- term = term * z * z / i
110
- i += 2.0
111
- end
112
+ while( sum + term != sum )
113
+ sum = sum + term
114
+ term = term * z * z / i
115
+ i += 2.0
116
+ end
112
117
 
113
- 0.5 + sum * phi(z)
114
- end
115
-
116
- # Standard Gaussian pdf
117
- def phi(x)
118
- numerator = exp(-1.0 * x*x / 2.0)
119
- denominator = sqrt(2.0 * PI)
120
- numerator / denominator
121
- end
118
+ 0.5 + sum * phi(z)
119
+ end
122
120
 
123
- end
121
+ # Standard Gaussian pdf
122
+ def phi(x)
123
+ numerator = exp(-1.0 * x*x / 2.0)
124
+ denominator = sqrt(2.0 * PI)
125
+ numerator / denominator
126
+ end
127
+
128
+ end
124
129
  end
125
130
  end
@@ -2,17 +2,17 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{options_library}
5
- s.version = "1.0.0"
5
+ s.version = "1.0.2"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Dan Tylenda-Emmons"]
9
- s.date = %q{2011-02-13}
9
+ s.date = %q{2011-02-16}
10
10
  s.description = %q{A gem used to calc the price of an option.}
11
11
  s.email = %q{jrubyist@gmail.com}
12
- s.extra_rdoc_files = ["lib/options_library.rb", "lib/options_library/option_calculator.rb"]
13
- s.files = ["Rakefile", "lib/options_library.rb", "lib/options_library/option_calculator.rb", "options_library.gemspec", "Manifest"]
12
+ s.extra_rdoc_files = ["README.md", "lib/options_library.rb", "lib/options_library/option_calculator.rb"]
13
+ s.files = ["Manifest", "README.md", "Rakefile", "lib/options_library.rb", "lib/options_library/option_calculator.rb", "options_library.gemspec"]
14
14
  s.homepage = %q{http://github.com/codertrader/options_library}
15
- s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Options_library"]
15
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Options_library", "--main", "README.md"]
16
16
  s.require_paths = ["lib"]
17
17
  s.rubyforge_project = %q{options_library}
18
18
  s.rubygems_version = %q{1.5.2}
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: options_library
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 1.0.0
5
+ version: 1.0.2
6
6
  platform: ruby
7
7
  authors:
8
8
  - Dan Tylenda-Emmons
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-02-13 00:00:00 -06:00
13
+ date: 2011-02-16 00:00:00 -06:00
14
14
  default_executable:
15
15
  dependencies: []
16
16
 
@@ -21,14 +21,16 @@ executables: []
21
21
  extensions: []
22
22
 
23
23
  extra_rdoc_files:
24
+ - README.md
24
25
  - lib/options_library.rb
25
26
  - lib/options_library/option_calculator.rb
26
27
  files:
28
+ - Manifest
29
+ - README.md
27
30
  - Rakefile
28
31
  - lib/options_library.rb
29
32
  - lib/options_library/option_calculator.rb
30
33
  - options_library.gemspec
31
- - Manifest
32
34
  has_rdoc: true
33
35
  homepage: http://github.com/codertrader/options_library
34
36
  licenses: []
@@ -39,6 +41,8 @@ rdoc_options:
39
41
  - --inline-source
40
42
  - --title
41
43
  - Options_library
44
+ - --main
45
+ - README.md
42
46
  require_paths:
43
47
  - lib
44
48
  required_ruby_version: !ruby/object:Gem::Requirement