stocks 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 14f408a3cbba0b2f34f833d80ffae64d800e96aa
4
+ data.tar.gz: 29f789edf2db4baeb8d0b4b33ce49a4330150f92
5
+ SHA512:
6
+ metadata.gz: afef568d14ca8380dd14e52b2ce32dec19160ca4b72fd6d684c32c41764fe1f02164a5e5178d3f06a08b2afc45c0bccb444f1e3c33389e9f3a545929316881a4
7
+ data.tar.gz: 87a7fbbf6601f962f2e07aabbb22ec251cd172a6a23ed5f39ab7bbe19b05a25816497765db1e62a1df526bf2c3632e03f40d49760dd3a414e385bdb8ea8b3be0
@@ -0,0 +1,11 @@
1
+ # Author:: Matt Fornaciari (mailto:mattforni@gmail.com)
2
+ # License:: MIT
3
+
4
+ module Stocks
5
+ class RetrievalError < RuntimeError
6
+ def new(message)
7
+ super(message)
8
+ end
9
+ end
10
+ end
11
+
@@ -0,0 +1,39 @@
1
+ # Author:: Matt Fornaciari (mailto:mattforni@gmail.com)
2
+ # License:: MIT
3
+
4
+ require 'active_support/core_ext/integer/time'
5
+
6
+ module Stocks
7
+ module Historical
8
+ PERIODS = {
9
+ one_month: {label: '1 Month', offset: 1.months},
10
+ three_months: {label: '3 Months', offset: 3.months},
11
+ six_months: {label: '6 Months', offset: 6.months},
12
+ one_year: {label: '1 Year', offset: 1.years},
13
+ five_years: {label: '5 Years', offset: 5.years}
14
+ }
15
+
16
+ def self.macd(symbol, days)
17
+ sma12 = self.sma(symbol, 12, days)
18
+ sma26 = self.sma(symbol, 26, days)
19
+ (0...days).collect { |day| sma12[day] - sma26[day] }
20
+ end
21
+
22
+ def self.sma(symbol, periods, days)
23
+ sma = []
24
+ days.downto(1).each do |day|
25
+ date = Date.today - day
26
+ quotes = YahooFinance::get_HistoricalQuotes(symbol, date - periods, date)
27
+ sma << quotes.reduce(0) { |total, q| total += q.close } / quotes.size
28
+ end
29
+ sma
30
+ end
31
+
32
+ def self.quote(symbol, period)
33
+ raise ArgumentError.new("Period must be provided for a historical quote") if period.nil?
34
+ raise ArgumentError.new("'#{period}' is not a supported period") if !PERIODS.has_key?(period.to_sym)
35
+ YahooFinance::get_HistoricalQuotes(symbol, Date.today - PERIODS[period.to_sym][:offset], Date.today)
36
+ end
37
+ end
38
+ end
39
+
@@ -0,0 +1,17 @@
1
+ # Author:: Matt Fornaciari (mailto:mattforni@gmail.com)
2
+ # License:: MIT
3
+
4
+ require 'active_model/validator'
5
+
6
+ module Stocks
7
+ module Validators
8
+ class Exists < ActiveModel::Validator
9
+ def validate(record)
10
+ if (!Stocks.exists?(record.symbol))
11
+ record.errors[:symbol] << "'#{record.symbol}' is not a valid symbol."
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+
data/lib/stocks.rb ADDED
@@ -0,0 +1,64 @@
1
+ # Author:: Matt Fornaciari (mailto:mattforni@gmail.com)
2
+ # License:: MIT
3
+
4
+ # Require external libraries
5
+ require 'yahoofinance'
6
+
7
+ # Require all Stocks related files
8
+ require 'stocks/errors'
9
+ require 'stocks/historical'
10
+ require 'stocks/validators/exists'
11
+
12
+ # TODO test this module
13
+ # TODO add a caching layer with 1-min TTL
14
+ module Stocks
15
+ COMMISSION_RANGE = {greater_than_or_equal_to: 0}
16
+ EPSILON = 0.00001
17
+ NA = 'N/A'
18
+ PRICE_RANGE = {greater_than: 0}
19
+ PRICE_SCALE = 5
20
+ PERCENTAGE_RANGE = {greater_than: 0, less_than: 100}
21
+ QUANTITY_RANGE = {greater_than: 0}
22
+
23
+ # TODO move to another lib module
24
+ def self.equal?(value, other)
25
+ (value-other).abs < EPSILON
26
+ end
27
+
28
+ # Determines whether or not the provided symbol exists.
29
+ #
30
+ # * *Args*:
31
+ # - +symbol+ The symbol to evaluate
32
+ # * *Returns*:
33
+ # - Whether or not the provided symbol exists
34
+ def self.exists?(symbol)
35
+ quote(symbol.upcase, [:date])[:date] != NA
36
+ end
37
+
38
+ # Fetches the last trade for the provided symbol.
39
+ #
40
+ # * *Args*:
41
+ # - +symbol+ The symbol to evaluate
42
+ # * *Returns*:
43
+ # - The last trade for the provided symbol
44
+ # * *Raises*:
45
+ # - +RetrievalError+ If the provided symbol does not exist
46
+ def self.last_trade(symbol)
47
+ last_trade = quote(symbol)[:lastTrade]
48
+ raise RetrievalError.new("Could not retrieve last trade for '#{symbol}'") if last_trade == 0 or last_trade == NA
49
+ last_trade
50
+ end
51
+
52
+ private
53
+
54
+ def self.quote(symbol, fields = [:lastTrade])
55
+ data = {}
56
+ # TODO use the fields map to decide which method to use
57
+ standard_quote = YahooFinance::get_standard_quotes(symbol)[symbol]
58
+ fields.each do |field|
59
+ data[field] = standard_quote.send(field) rescue NA
60
+ end
61
+ data
62
+ end
63
+ end
64
+
metadata ADDED
@@ -0,0 +1,103 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: stocks
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Matthew Fornaciari
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-05-05 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: yahoofinance
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.2'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.2'
27
+ - !ruby/object:Gem::Dependency
28
+ name: activesupport
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '4.2'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '4.2'
41
+ - !ruby/object:Gem::Dependency
42
+ name: activerecord
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '4.2'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '4.2'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '2'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '2'
69
+ description: A programmatic approach to performing various financial analysis
70
+ email: mattforni@gmail.com
71
+ executables: []
72
+ extensions: []
73
+ extra_rdoc_files: []
74
+ files:
75
+ - lib/stocks.rb
76
+ - lib/stocks/errors.rb
77
+ - lib/stocks/historical.rb
78
+ - lib/stocks/validators/exists.rb
79
+ homepage: http://rubygems.org/gems/stocks
80
+ licenses:
81
+ - MIT
82
+ metadata: {}
83
+ post_install_message: Now go make yourself some money!
84
+ rdoc_options: []
85
+ require_paths:
86
+ - lib
87
+ required_ruby_version: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ version: '0'
92
+ required_rubygems_version: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ requirements: []
98
+ rubyforge_project:
99
+ rubygems_version: 2.4.6
100
+ signing_key:
101
+ specification_version: 4
102
+ summary: Provides a library for analyzing stocks
103
+ test_files: []