options-lib 0.9.2 → 0.9.4

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.
@@ -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