stock_history 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 33f1883ebe03f8b4244524165005fc7ed9ed6dd3
4
+ data.tar.gz: 80d10469b2ff68994aeb066c1874b94ac484f387
5
+ SHA512:
6
+ metadata.gz: fb009d779cd6af8c08802f0701a6798c887a3b54a5c61633765c366485756646874f6bd11536b1766bce749a8df84bb905432b5c1471eac384e669903cba23f0
7
+ data.tar.gz: d7633961a3df96182f7cd22583a29dffe0c574f0d6e36b7bd3fdcdac59d23ad6243594d31339e996c96816cac21a9c8f54ece709dfe54625e1dff8e5779b1c03
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.3.0
5
+ before_install: gem install bundler -v 1.13.6
@@ -0,0 +1,74 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to making participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age, body
8
+ size, disability, ethnicity, gender identity and expression, level of experience,
9
+ nationality, personal appearance, race, religion, or sexual identity and
10
+ orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
16
+
17
+ * Using welcoming and inclusive language
18
+ * Being respectful of differing viewpoints and experiences
19
+ * Gracefully accepting constructive criticism
20
+ * Focusing on what is best for the community
21
+ * Showing empathy towards other community members
22
+
23
+ Examples of unacceptable behavior by participants include:
24
+
25
+ * The use of sexualized language or imagery and unwelcome sexual attention or
26
+ advances
27
+ * Trolling, insulting/derogatory comments, and personal or political attacks
28
+ * Public or private harassment
29
+ * Publishing others' private information, such as a physical or electronic
30
+ address, without explicit permission
31
+ * Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Our Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying the standards of acceptable
37
+ behavior and are expected to take appropriate and fair corrective action in
38
+ response to any instances of unacceptable behavior.
39
+
40
+ Project maintainers have the right and responsibility to remove, edit, or
41
+ reject comments, commits, code, wiki edits, issues, and other contributions
42
+ that are not aligned to this Code of Conduct, or to ban temporarily or
43
+ permanently any contributor for other behaviors that they deem inappropriate,
44
+ threatening, offensive, or harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies both within project spaces and in public spaces
49
+ when an individual is representing the project or its community. Examples of
50
+ representing a project or community include using an official project e-mail
51
+ address, posting via an official social media account, or acting as an appointed
52
+ representative at an online or offline event. Representation of a project may be
53
+ further defined and clarified by project maintainers.
54
+
55
+ ## Enforcement
56
+
57
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
+ reported by contacting the project team at unieagle@gmail.com. All
59
+ complaints will be reviewed and investigated and will result in a response that
60
+ is deemed necessary and appropriate to the circumstances. The project team is
61
+ obligated to maintain confidentiality with regard to the reporter of an incident.
62
+ Further details of specific enforcement policies may be posted separately.
63
+
64
+ Project maintainers who do not follow or enforce the Code of Conduct in good
65
+ faith may face temporary or permanent repercussions as determined by other
66
+ members of the project's leadership.
67
+
68
+ ## Attribution
69
+
70
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
+ available at [http://contributor-covenant.org/version/1/4][version]
72
+
73
+ [homepage]: http://contributor-covenant.org
74
+ [version]: http://contributor-covenant.org/version/1/4/
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in stock_history.gemspec
4
+ gemspec
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 uniEagle
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,53 @@
1
+ # StockHistory
2
+
3
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/stock_history`. To experiment with that code, run `bin/console` for an interactive prompt.
4
+
5
+ TODO: Delete this and the text above, and describe your gem
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'stock_history'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install stock_history
22
+
23
+ ## Usage
24
+
25
+ Daily history with splits:
26
+
27
+ ```ruby
28
+ StockHistory.history('DRYS', :start_date => '2017-01-20', :stop_date => '2017-01-25')
29
+ # => [{:date=>"20170125", :date_parsed=>#<Date: 2017-01-25 ((2457779j,0s,0n),+0s,2299161j)>, :open=>4.48, :high=>4.74, :low=>3.98, :close=>4.0, :volume=>12492400.0, :adjusted_close=>4.0, :split=>nil, :merge=>nil, :dividend=>nil}, {:date=>"20170124", :date_parsed=>#<Date: 2017-01-24 ((2457778j,0s,0n),+0s,2299161j)>, :open=>5.56, :high=>5.6, :low=>4.42, :close=>4.48, :volume=>20733100.0, :adjusted_close=>4.48, :split=>nil, :merge=>nil, :dividend=>nil}, {:date=>"20170123", :date_parsed=>#<Date: 2017-01-23 ((2457777j,0s,0n),+0s,2299161j)>, :open=>7.5, :high=>7.65, :low=>5.25, :close=>5.4, :volume=>13820800.0, :adjusted_close=>5.4, :split=>1.0, :merge=>8.0, :dividend=>nil}, {:date=>"20170120", :date_parsed=>#<Date: 2017-01-20 ((2457774j,0s,0n),+0s,2299161j)>, :open=>1.04, :high=>1.13, :low=>0.99, :close=>1.01, :volume=>6841800.0, :adjusted_close=>8.08, :split=>nil, :merge=>nil, :dividend=>nil}]
30
+ ```
31
+
32
+ Daily history with dividend:
33
+
34
+ ```ruby
35
+ StockHistory.history('GDXJ', :start_date => '2016-12-18', :stop_date => '2016-12-21')
36
+ # => [{:date=>"20161221", :date_parsed=>#<Date: 2016-12-21 ((2457744j,0s,0n),+0s,2299161j)>, :open=>28.62, :high=>28.75, :low=>28.13, :close=>28.18, :volume=>11546800.0, :adjusted_close=>28.18, :split=>nil, :merge=>nil, :dividend=>nil}, {:date=>"20161220", :date_parsed=>#<Date: 2016-12-20 ((2457743j,0s,0n),+0s,2299161j)>, :open=>27.71, :high=>28.63, :low=>27.37, :close=>28.51, :volume=>23996800.0, :adjusted_close=>28.51, :split=>nil, :merge=>nil, :dividend=>nil}, {:date=>"20161219", :date_parsed=>#<Date: 2016-12-19 ((2457742j,0s,0n),+0s,2299161j)>, :open=>28.89, :high=>28.92, :low=>28.12, :close=>28.43, :volume=>27938700.0, :adjusted_close=>28.43, :split=>nil, :merge=>nil, :dividend=>1.51}, {:date=>"20161216", :date_parsed=>#<Date: 2016-12-16 ((2457739j,0s,0n),+0s,2299161j)>, :open=>30.81, :high=>31.18, :low=>29.53, :close=>29.86, :volume=>23705400.0, :adjusted_close=>28.35, :split=>nil, :merge=>nil, :dividend=>nil}]
37
+ ```
38
+
39
+ ## Development
40
+
41
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
42
+
43
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
44
+
45
+ ## Contributing
46
+
47
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/stock_history. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
48
+
49
+
50
+ ## License
51
+
52
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
53
+
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "stock_history"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,138 @@
1
+ require "stock_history/version"
2
+ require 'net/http'
3
+ require 'json'
4
+ require 'date'
5
+ require 'stock_history/utility.rb'
6
+ require 'stock_history/exceptions.rb'
7
+ include StockHistory::Utility
8
+
9
+ module StockHistory
10
+
11
+ # Get daily history for a symbol
12
+ # Available params:
13
+ # :start_date => '2016-01-01'
14
+ # :end_date => Date.today.to_s
15
+ # :freq => 'd', 'w' or 'm'
16
+ def self.history(symbol, params={})
17
+ his_params = {}
18
+ his_params[:start_date] = to_date(params[:start_date])
19
+ his_params[:stop_date] = to_date(params[:stop_date])
20
+ his_params[:freq] = (%w(d w m).include?(params[:freq]) ? params[:freq] : 'd')
21
+
22
+ url = build_url(symbol, his_params)
23
+ uri = URI(url)
24
+ response = Net::HTTP.get(uri)
25
+ parse_response(response)
26
+ end
27
+
28
+ private
29
+ def self.parse_response(response)
30
+ results = []
31
+ lines = response.split("\n")
32
+
33
+ if lines.count <= 5
34
+ raise ParseException.new("Response format not correct")
35
+ end
36
+
37
+ # Date,Open,High,Low,Close,Volume,Adj Close
38
+ if lines[0] != "Date,Open,High,Low,Close,Volume,Adj Close"
39
+ raise ParseException.new("Header not correct")
40
+ end
41
+
42
+ if lines[-1] != "STATUS, 0"
43
+ raise ParseException.new("Status not correct")
44
+ end
45
+
46
+ # TOTALSIZE, 24
47
+ total_size = 0
48
+ unless lines[-2].start_with?("TOTALSIZE")
49
+ raise ParseException.new("Size not parsed out")
50
+ else
51
+ total_size = lines[-2].split(',').last.to_i
52
+ end
53
+
54
+ # STARTDATE, 20161230
55
+ # ENDDATE, 20170203
56
+ start_date = nil
57
+ end_date = nil
58
+ unless lines[-3].start_with?("ENDDATE") or lines[-4].start_with?("STARTDATE")
59
+ raise ParseException.new("Dates not parsed out")
60
+ else
61
+ start_date = lines[-4].split(',').last.strip
62
+ end_date = lines[-3].split(',').last.strip
63
+ end
64
+
65
+ dividends = {}
66
+ splits = {}
67
+
68
+ lines[1..-5].each do |line|
69
+ # puts line
70
+
71
+ elements = line.split(",").map(&:strip)
72
+ if elements.first == 'SPLIT'
73
+ # this is reverse split (merge), and will apear above the daily history on that day
74
+ # SPLIT, 20170123,1:8
75
+ rates = elements.last.split(':').map(&:to_f)
76
+ splits[elements[1]] = {
77
+ :date => elements[1],
78
+ :split => rates[0] < rates[1] ? 1.0 : rates[0] / rates[1],
79
+ :merge => rates[0] < rates[1] ? rates[1] / rates[0] : 1.0
80
+ }
81
+ elsif elements.first == 'DIVIDEND'
82
+ # this will apear above the daily history on that day
83
+ # DIVIDEND, 20161219,1.507000
84
+ dividends[elements[1]] = {
85
+ :date => elements[1],
86
+ :dividend => elements[2].to_f.round(2)
87
+ }
88
+ else
89
+ # Date,Open,High,Low,Close,Volume,Adj Close
90
+ # 20161219,28.889999,28.92,28.120001,28.43,27938700,28.43
91
+ trading_date = to_date(elements.first)
92
+ if trading_date.nil?
93
+ raise ParseException.new("Format error on line: #{line}")
94
+ end
95
+ results << {
96
+ :date => elements[0],
97
+ :date_parsed => to_date(elements[0]),
98
+ :open => elements[1].to_f.round(2),
99
+ :high => elements[2].to_f.round(2),
100
+ :low => elements[3].to_f.round(2),
101
+ :close => elements[4].to_f.round(2),
102
+ :volume => elements[5].to_f.round(2),
103
+ :adjusted_close => elements[6].to_f.round(2),
104
+ :split => splits[elements[0]] == nil ? nil : splits[elements[0]][:split],
105
+ :merge => splits[elements[0]] == nil ? nil : splits[elements[0]][:merge],
106
+ :dividend => dividends[elements[0]] == nil ? nil : dividends[elements[0]][:dividend],
107
+ }
108
+ end
109
+ end
110
+
111
+ results
112
+ end
113
+
114
+ def self.build_url(symbol, params={})
115
+ params[:start_date] ||= Date.parse('2016-01-01')
116
+ params[:stop_date] ||= Date.today
117
+ params[:freq] ||= 'd'
118
+
119
+ url_params = {}
120
+ url_params['s'] = symbol.upcase
121
+ url_params['a'] = params[:start_date].month - 1
122
+ url_params['b'] = params[:start_date].day
123
+ url_params['c'] = params[:start_date].year
124
+ url_params['d'] = params[:stop_date].month - 1
125
+ url_params['e'] = params[:stop_date].day
126
+ url_params['f'] = params[:stop_date].year
127
+ url_params['g'] = params[:freq]
128
+ url_params['y'] = '0'
129
+ url_params['z'] = '30000'
130
+
131
+ url = 'http://real-chart.finance.yahoo.com/x?'
132
+ url_params.keys.sort.each do |key|
133
+ url += "&#{key}=#{url_params[key]}"
134
+ end
135
+
136
+ url
137
+ end
138
+ end
@@ -0,0 +1,4 @@
1
+ module StockHistory
2
+ class ParseException < Exception
3
+ end
4
+ end
@@ -0,0 +1,50 @@
1
+
2
+ require 'date'
3
+ module StockHistory
4
+ # => StockHistory Utility Methods
5
+ module Utility
6
+
7
+ def min_date(first, second)
8
+ first < second ? first : second
9
+ end
10
+
11
+ def to_format(string)
12
+ to_fs(to_date(string))
13
+ end
14
+
15
+ def to_underscore(string)
16
+ string = string.gsub(/::/, '/')
17
+ string.gsub!(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
18
+ string.gsub!(/([a-z\d])([A-Z])/, '\1_\2')
19
+ string.tr!('-', '_')
20
+ string.downcase!
21
+ string
22
+ end
23
+
24
+ def to_fs(string)
25
+ (!!Float(string) rescue false) ? Float(string) : string
26
+ end
27
+
28
+ def to_p(string)
29
+ if string.is_a?(String)
30
+ to_p(string.split(','))
31
+ elsif string.is_a?(Array)
32
+ "'#{string.join("','").gsub(" ", "").upcase}'"
33
+ else
34
+ string
35
+ end
36
+ end
37
+
38
+ def to_date(string)
39
+ if string.is_a?(String) && string.match(/\d{4}-\d{2}-\d{2}/)
40
+ Date.strptime(string, '%Y-%m-%d')
41
+ elsif string.is_a?(String) && string.match(/\d{2}\/\d{2}\/\d{4}/)
42
+ Date.strptime(string, '%m/%d/%Y')
43
+ elsif string.is_a?(String) && string.match(/\d{8}/)
44
+ Date.strptime(string, '%Y%m%d')
45
+ else
46
+ string
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,3 @@
1
+ module StockHistory
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,36 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'stock_history/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "stock_history"
8
+ spec.version = StockHistory::VERSION
9
+ spec.authors = ["uniEagle"]
10
+ spec.email = ["unieagle@gmail.com"]
11
+
12
+ spec.summary = "Get stock history data from Yahoo, with split and dividend info"
13
+ spec.description = "Get stock history data from Yahoo, with split and dividend info"
14
+ spec.homepage = "https://github.com/unieagle/stock_history"
15
+ spec.license = "MIT"
16
+
17
+ # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
18
+ # to allow pushing to a single host or delete this section to allow pushing to any host.
19
+ # if spec.respond_to?(:metadata)
20
+ # spec.metadata['allowed_push_host'] = "TODO: Set to 'http://mygemserver.com'"
21
+ # else
22
+ # raise "RubyGems 2.0 or newer is required to protect against " \
23
+ # "public gem pushes."
24
+ # end
25
+
26
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
27
+ f.match(%r{^(test|spec|features)/})
28
+ end
29
+ spec.bindir = "exe"
30
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
31
+ spec.require_paths = ["lib"]
32
+
33
+ spec.add_development_dependency "bundler", "~> 1.13"
34
+ spec.add_development_dependency "rake", "~> 10.0"
35
+ spec.add_development_dependency "rspec", "~> 3.0"
36
+ end
metadata ADDED
@@ -0,0 +1,101 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: stock_history
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - uniEagle
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2017-02-06 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.13'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.13'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ description: Get stock history data from Yahoo, with split and dividend info
56
+ email:
57
+ - unieagle@gmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - ".gitignore"
63
+ - ".rspec"
64
+ - ".travis.yml"
65
+ - CODE_OF_CONDUCT.md
66
+ - Gemfile
67
+ - LICENSE.txt
68
+ - README.md
69
+ - Rakefile
70
+ - bin/console
71
+ - bin/setup
72
+ - lib/stock_history.rb
73
+ - lib/stock_history/exceptions.rb
74
+ - lib/stock_history/utility.rb
75
+ - lib/stock_history/version.rb
76
+ - stock_history.gemspec
77
+ homepage: https://github.com/unieagle/stock_history
78
+ licenses:
79
+ - MIT
80
+ metadata: {}
81
+ post_install_message:
82
+ rdoc_options: []
83
+ require_paths:
84
+ - lib
85
+ required_ruby_version: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ required_rubygems_version: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ requirements: []
96
+ rubyforge_project:
97
+ rubygems_version: 2.5.1
98
+ signing_key:
99
+ specification_version: 4
100
+ summary: Get stock history data from Yahoo, with split and dividend info
101
+ test_files: []