options-lib 0.9.2 → 0.9.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -3,7 +3,62 @@
3
3
  A set of classes for dealing with options. It includes a crawler for Yahoo!Finance. The crawler has an internal
4
4
  thread that can be started to periodically update the option quotes.
5
5
 
6
+ ## Install
7
+
8
+ gem install options-lib
9
+
6
10
  ## Usage
7
11
 
8
- TODO
12
+ require 'options-lib'
13
+
14
+ # Create a crawler for all the options for ('AAPL') expiring on '2013-01-18'
15
+ y = YahooCrawler.new('AAPL', '2013-01-18')
16
+
17
+ # Fetch the entire options chain for this stock and expiration
18
+ y.fetch
19
+
20
+ # Show an option quote for a given strike price
21
+ y.call_options[300] # => AAPL_C300_18JAN2013: bid => 88.5, ask => 90.5
22
+ y.put_options[300] # => AAPL_P300_18JAN2013: bid => 40.7, ask => 41.95
23
+
24
+ # Options quote has stock price, bid and ask for option
25
+ q = y.call_options[300]
26
+ q.stock_price # => 342.88
27
+ q.bid # => 88.5
28
+ q.ask # => 90.5
29
+
30
+ # Crawler also has current stock price, as each option quote
31
+ y.stock_price # => 342.88
32
+
33
+ # You can get a list of all stock prices from the crawler
34
+ y.call_strikes # => [135.0, 140.0, ..., 530.0, 540.0]
35
+ y.put_strikes # => [135.0, 140.0, ..., 530.0, 540.0]
36
+
37
+ # So to print the entire options chain, you can do something like that
38
+ y.call_strikes.each { |strike| puts y.call_options[strike] }
39
+ y.put_strikes.each { |strike| puts y.put_options[strike] }
40
+
41
+ # you can place the crawler in auto_reload mode, passing a period to refresh itself
42
+ y.auto_reload 5
43
+ y.call_options[300].bid # => 88.5
44
+ sleep 6
45
+ y.call_options[300].bid # => 90.3
46
+
47
+ # you can also receive callbacks from the internal thread when the crawler gets updated
48
+ y.auto_reload(5) do
49
+ puts "Current bid: #{y.call_options[300].bid}"
50
+ end
51
+
52
+ # if you need to block ruby from exiting while your thread is executing in the background
53
+ # you can use the method below
54
+ y.join_reload_thread
55
+
56
+ # internal symbol versus real symbol
57
+ y.internal_symbol # => AAPL_C300_18JAN2013
58
+ y.symbol # => AAPL130119C00300000
59
+
60
+
61
+
62
+
63
+
9
64
 
@@ -0,0 +1,56 @@
1
+ require 'rubygems'
2
+
3
+ def gemspec
4
+ @gemspec ||= begin
5
+ file = File.expand_path("../options-lib.gemspec", __FILE__)
6
+ eval(File.read(file), binding, file)
7
+ end
8
+ end
9
+
10
+ def alias_task(old_task, new_task)
11
+ task new_task do
12
+ Rake::Task[old_task].invoke
13
+ end
14
+ end
15
+
16
+
17
+ desc "Validate the gemspec"
18
+ task :gemspec do
19
+ gemspec.validate
20
+ end
21
+
22
+ desc "Build gem locally"
23
+ task :build => :gemspec do
24
+ system "gem build #{gemspec.name}.gemspec"
25
+ FileUtils.mkdir_p "pkg"
26
+ FileUtils.mv "#{gemspec.name}-#{gemspec.version}.gem", "pkg"
27
+ end
28
+
29
+ desc "Install gem locally"
30
+ task :install => :build do
31
+ system "gem install pkg/#{gemspec.name}-#{gemspec.version}"
32
+ end
33
+
34
+ desc "Uninstall gem locally"
35
+ task :uninstall => :gemspec do
36
+ system "gem uninstall -x #{gemspec.name}"
37
+ end
38
+
39
+ desc "Reinstall gem locally"
40
+ task :reinstall do
41
+ Rake::Task[:uninstall].invoke
42
+ Rake::Task[:install].invoke
43
+ end
44
+
45
+ desc "Push gem to RubyGems.org"
46
+ task :push do
47
+ system "gem push pkg/#{gemspec.name}-#{gemspec.version}.gem"
48
+ end
49
+
50
+ alias_task(:reinstall, :r)
51
+ alias_task(:uninstall, :u)
52
+ alias_task(:install, :i)
53
+ alias_task(:build, :b)
54
+ alias_task(:push, :p)
55
+
56
+
@@ -25,7 +25,7 @@ y.auto_reload(reload_period) do
25
25
 
26
26
  options = is_call ? y.call_options : y.put_options
27
27
  quote = options[strike]
28
- stock_price = y.curr_stock_price
28
+ stock_price = y.stock_price
29
29
 
30
30
  puts "Stock @ #{stock_price} Options: #{quote.bid} | #{quote.ask} Spread: #{quote.spread}"
31
31
 
@@ -2,12 +2,13 @@ require_relative 'option'
2
2
 
3
3
  class OptionQuote
4
4
 
5
- attr_reader :option, :bid, :ask
5
+ attr_reader :option, :bid, :ask, :stock_price
6
6
 
7
7
  def initialize(option, args)
8
8
  @option = option
9
9
  @bid = args[:bid] || nil
10
10
  @ask = args[:ask] || nil
11
+ @stock_price = args[:stock_price] || nil
11
12
  end
12
13
 
13
14
  def spread
@@ -19,11 +20,7 @@ class OptionQuote
19
20
  end
20
21
 
21
22
  def to_s
22
- "#{option.to_s}: #{bid.inspect} / #{ask.inspect}"
23
- end
24
-
25
- def inspect
26
- "#{option.inspect}: bid => #{bid.inspect}, ask => #{ask.inspect}"
23
+ "#{option}: bid => #{bid}, ask => #{ask}"
27
24
  end
28
25
 
29
26
  end
@@ -11,9 +11,9 @@ class YahooCrawler
11
11
 
12
12
  def initialize(stock, exp)
13
13
  @mech = Mechanize.new
14
- @stock, @exp = stock, exp
14
+ @stock, @exp = stock.upcase, exp
15
15
  @url = "http://finance.yahoo.com/q/op?s=#{stock}&m=#{exp[0,7]}"
16
- @stock_curr_price = nil
16
+ @stock_price = nil
17
17
  @call_options = Hash.new
18
18
  @put_options = Hash.new
19
19
  @call_strikes = Array.new
@@ -23,6 +23,10 @@ class YahooCrawler
23
23
  @thread = nil
24
24
  end
25
25
 
26
+ def to_s
27
+ "YahooCrawler('#{@stock}','#{@exp})"
28
+ end
29
+
26
30
  def auto_reload(period = 60)
27
31
  if not @thread.nil?
28
32
  stop
@@ -58,6 +62,9 @@ class YahooCrawler
58
62
  c_options, p_options = Hash.new, Hash.new
59
63
  c_strikes, p_strikes = Array.new, Array.new
60
64
  stock_price = nil
65
+
66
+ # A small hack to make my hashes accept integers instead of floats for the strike prices
67
+ add_convert_method_for_keys(c_options, p_options)
61
68
 
62
69
  @t_lock.synchronize { # don't step into each other in case someone calls fetch
63
70
 
@@ -74,7 +81,7 @@ class YahooCrawler
74
81
  lines = lines.chunk(lines.length / 8)
75
82
 
76
83
  lines.each do |array|
77
- quote = parse_quote(array, Option::CALL)
84
+ quote = parse_quote(array, Option::CALL, stock_price)
78
85
  c_options[quote.option.strike] = quote
79
86
  end
80
87
 
@@ -82,7 +89,7 @@ class YahooCrawler
82
89
  lines = lines.chunk(lines.length / 8)
83
90
 
84
91
  lines.each do |array|
85
- quote = parse_quote(array, Option::PUT)
92
+ quote = parse_quote(array, Option::PUT, stock_price)
86
93
  p_options[quote.option.strike] = quote
87
94
  end
88
95
 
@@ -95,9 +102,9 @@ class YahooCrawler
95
102
  @lock.synchronize {
96
103
  @call_options, @put_options = c_options, p_options
97
104
  @call_strikes, @put_strikes = c_strikes, p_strikes
98
- @curr_stock_price = stock_price
105
+ @stock_price = stock_price
99
106
  }
100
-
107
+ nil
101
108
  end
102
109
 
103
110
  def get_option_quote(type, strike)
@@ -132,8 +139,8 @@ class YahooCrawler
132
139
  @lock.synchronize { @put_options }
133
140
  end
134
141
 
135
- def curr_stock_price
136
- @lock.synchronize { @curr_stock_price }
142
+ def stock_price
143
+ @lock.synchronize { @stock_price }
137
144
  end
138
145
 
139
146
  def show_calls
@@ -146,14 +153,14 @@ class YahooCrawler
146
153
 
147
154
  private
148
155
 
149
- def parse_quote(line, type)
156
+ def parse_quote(line, type, stock_price)
150
157
  strike = line[0].to_f
151
158
  symbol = line[1]
152
159
  bid = f line[4]
153
160
  ask = f line[5]
154
161
 
155
162
  o = Option.new(type, @stock, strike, @exp, symbol)
156
- OptionQuote.new(o, :bid => bid, :ask => ask)
163
+ OptionQuote.new(o, :bid => bid, :ask => ask, :stock_price => stock_price)
157
164
  end
158
165
 
159
166
  # Get all values inside tags
@@ -165,5 +172,14 @@ class YahooCrawler
165
172
  def f(data)
166
173
  data == 'N/A' ? nil : data.to_f
167
174
  end
175
+
176
+ def add_convert_method_for_keys(*args)
177
+ args.each do |obj|
178
+ def obj.[](key)
179
+ super key.to_f
180
+ end
181
+ end
182
+
183
+ end
168
184
 
169
185
  end
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'options-lib'
3
- s.version = '0.9.2'
3
+ s.version = '0.9.4'
4
4
  s.platform = Gem::Platform::RUBY
5
5
  s.summary = 'Options Library'
6
6
  s.description = 'A set of classes for dealing with options. It includes a crawler for Yahoo!Finance.'
@@ -3,10 +3,15 @@ Dir["./lib/*.rb"].each {|file| require file }
3
3
 
4
4
  describe OptionQuote do
5
5
 
6
+ o,q = nil,nil
7
+
8
+ before(:all) do
9
+ o = Option.new(Option::CALL, 'AAPL', 250, '2010-02-14')
10
+ q = OptionQuote.new(o, :bid => 1.2, :ask => 1.4, :stock_price => 10)
11
+ end
12
+
6
13
  it 'has option, bid and ask prices' do
7
14
 
8
- o = Option.new(Option::CALL, 'AAPL', 250, '2010-02-14')
9
- q = OptionQuote.new(o, :bid => 1.2, :ask => 1.4)
10
15
  q.option.should == o
11
16
  q.bid.should == 1.2
12
17
  q.ask.should == 1.4
@@ -14,10 +19,12 @@ describe OptionQuote do
14
19
  end
15
20
 
16
21
  it 'should have an spread' do
17
- o = Option.new(Option::CALL, 'AAPL', 250, '2010-02-14')
18
- q = OptionQuote.new(o, :bid => 1.2, :ask => 1.4)
19
22
  q.spread.prettify.should == "0.2"
20
23
 
21
24
  end
22
25
 
26
+ it 'should have the current stock price' do
27
+ q.stock_price.should == 10
28
+ end
29
+
23
30
  end
@@ -19,7 +19,7 @@ describe YahooCrawler do
19
19
 
20
20
  it 'should be able to get current price of stock' do
21
21
 
22
- y.curr_stock_price.should > 0
22
+ y.stock_price.should > 0
23
23
 
24
24
  end
25
25
 
@@ -33,17 +33,19 @@ describe YahooCrawler do
33
33
  it 'should be able to give an option quote by strike price' do
34
34
 
35
35
  # get a good strike price by rounding the current stock price
36
- good_price = ((y.curr_stock_price / 100).to_i * 100).to_f
36
+ good_price = ((y.stock_price / 100).to_i * 100).to_f
37
37
 
38
38
  call_quote = y.call_options[good_price]
39
39
  call_quote.option.internal_symbol.should == "AAPL_C#{good_price.to_i}_18JAN2013"
40
40
  call_quote.bid.should > 0 if not call_quote.bid.nil?
41
41
  call_quote.ask.should > 0 if not call_quote.ask.nil?
42
+ call_quote.stock_price.should > 0 if not call_quote.stock_price.nil?
42
43
 
43
44
  put_quote = y.put_options[good_price]
44
45
  put_quote.option.internal_symbol.should == "AAPL_P#{good_price.to_i}_18JAN2013"
45
46
  put_quote.bid.should > 0 if not put_quote.bid.nil?
46
47
  put_quote.ask.should > 0 if not put_quote.ask.nil?
48
+ put_quote.stock_price.should > 0 if not put_quote.stock_price.nil?
47
49
 
48
50
  end
49
51
 
@@ -54,6 +56,13 @@ describe YahooCrawler do
54
56
  y.put_options.length.should > 0
55
57
 
56
58
  end
59
+
60
+ it 'should accept integers as well as floats for strike prices when accessing the options hash' do
61
+
62
+ y.call_options[300].should == y.call_options[300.0]
63
+
64
+ end
65
+
57
66
 
58
67
 
59
68
  end
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: options-lib
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.9.2
5
+ version: 0.9.4
6
6
  platform: ruby
7
7
  authors:
8
8
  - Sergio Oliveira Jr.
@@ -45,6 +45,7 @@ extra_rdoc_files: []
45
45
 
46
46
  files:
47
47
  - README.markdown
48
+ - Rakefile
48
49
  - bin/show_quotes
49
50
  - lib/options-lib.rb
50
51
  - lib/options-lib/helpers.rb