stocks 0.0.1

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 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: []