stocksy 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +33 -0
- data/bin/stocksy +12 -0
- data/lib/stocksy/alpha_vantage/api_key.rb +32 -0
- data/lib/stocksy/alpha_vantage.rb +52 -0
- data/lib/stocksy/asset/overview.rb +14 -0
- data/lib/stocksy/asset/profitability.rb +35 -0
- data/lib/stocksy/asset.rb +35 -0
- data/lib/stocksy/cli.rb +74 -0
- data/lib/stocksy/search.rb +9 -0
- data/lib/stocksy/version.rb +5 -0
- data/lib/stocksy.rb +12 -0
- metadata +99 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: f0658fd1d695020d19b5c09160524f0d76678600d96723086abf4c574580af25
|
4
|
+
data.tar.gz: 45fc1f6edf80ce5e4671b0903c307cdd4fe912dbf3a1fd1516cef771a0315a0c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: f3bf475c3567ec32cafb9cefcaba51739069705c0f2373cfa68a5415021737542c1c3c1547c003dc975e37f6d07a46edd210e7b99cb185a8cbe71c29cde11082
|
7
|
+
data.tar.gz: e72670c3dbe37c1171c03b26930b3a782036f6501bbfd063460de68a231ba5b57eb1634406d8d5d669460912f0260997a539f5afe12bb4c7947bb37070725d06
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2023 Bruno Prieto
|
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.
|
data/README.md
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# Stocksy
|
2
|
+
|
3
|
+
Stocksy is a command line tool that displays stock market information obtained from the [Alpha Vantage API](https://www.alphavantage.co/).
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Install the gem by executing:
|
8
|
+
|
9
|
+
$ gem install stocksy
|
10
|
+
|
11
|
+
## Usage
|
12
|
+
|
13
|
+
Get a free API key from [Alpha Vantage](https://www.alphavantage.co/) and set it up with `stocksy login [API key]` or with the "ALPHA_VANTAGE_API_KEY" environment variable so Stocksy can get data.
|
14
|
+
|
15
|
+
You can review the full list of commands by running `stocksy help`.
|
16
|
+
|
17
|
+
## Development
|
18
|
+
|
19
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
20
|
+
|
21
|
+
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 the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
22
|
+
|
23
|
+
## Contributing
|
24
|
+
|
25
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/brunoprietog/stocksy. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/brunoprietog/stocksy/blob/master/CODE_OF_CONDUCT.md).
|
26
|
+
|
27
|
+
## License
|
28
|
+
|
29
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
30
|
+
|
31
|
+
## Code of Conduct
|
32
|
+
|
33
|
+
Everyone interacting in the Stocksy project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/brunoprietog/stocksy/blob/master/CODE_OF_CONDUCT.md).
|
data/bin/stocksy
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Stocksy::AlphaVantage::ApiKey
|
4
|
+
extend self
|
5
|
+
FILE_PATH = File.join(Dir.home, ".stocksy")
|
6
|
+
|
7
|
+
def fetch
|
8
|
+
api_key = ENV.fetch("ALPHA_VANTAGE_API_KEY") do
|
9
|
+
ENV["ALPHA_VANTAGE_API_KEY"] = retrieve_api_key_from_file
|
10
|
+
end
|
11
|
+
api_key || raise(Stocksy::Error, "No API key found")
|
12
|
+
end
|
13
|
+
|
14
|
+
def save(api_key)
|
15
|
+
File.write(FILE_PATH, api_key)
|
16
|
+
end
|
17
|
+
|
18
|
+
def delete
|
19
|
+
return unless File.exist?(FILE_PATH)
|
20
|
+
|
21
|
+
File.delete(FILE_PATH)
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def retrieve_api_key_from_file
|
27
|
+
return unless File.exist? FILE_PATH
|
28
|
+
|
29
|
+
api_key = File.read(FILE_PATH).strip
|
30
|
+
return api_key unless api_key.empty?
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "net/http"
|
4
|
+
require "json"
|
5
|
+
require "active_support/inflector"
|
6
|
+
require "active_support/ordered_options"
|
7
|
+
|
8
|
+
module Stocksy::AlphaVantage
|
9
|
+
extend self
|
10
|
+
URL = "https://www.alphavantage.co/query"
|
11
|
+
|
12
|
+
def overview(symbol)
|
13
|
+
response = get(function: "OVERVIEW", symbol:)
|
14
|
+
optionize(response)
|
15
|
+
end
|
16
|
+
|
17
|
+
def get_time_series_dayly(symbol)
|
18
|
+
response = get(function: "TIME_SERIES_DAILY", symbol:, outputsize: "full")
|
19
|
+
normalize_response(response["Time Series (Daily)"])
|
20
|
+
end
|
21
|
+
|
22
|
+
def search(keywords)
|
23
|
+
response = get(function: "SYMBOL_SEARCH", keywords:)
|
24
|
+
normalize_response(response["bestMatches"])
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def get(params)
|
30
|
+
uri = URI.parse(URL)
|
31
|
+
uri.query = URI.encode_www_form(params.merge(apikey: api_key))
|
32
|
+
response = Net::HTTP.get(uri)
|
33
|
+
JSON.parse(response)
|
34
|
+
end
|
35
|
+
|
36
|
+
def api_key
|
37
|
+
ApiKey.fetch
|
38
|
+
end
|
39
|
+
|
40
|
+
def normalize_response(response)
|
41
|
+
if response.is_a?(Array)
|
42
|
+
response.map! { |hash| optionize(hash) }
|
43
|
+
elsif response.is_a?(Hash)
|
44
|
+
response.transform_values! { |hash| optionize(hash) }
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def optionize(hash)
|
49
|
+
hash.transform_keys! { |key| key.split.last.underscore.to_sym }
|
50
|
+
ActiveSupport::InheritableOptions.new(hash)
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Stocksy::Asset::Overview
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
delegate :name, :asset_type, :description, :exchange, :currency, :country, :sector, :industry,
|
8
|
+
:dividend_per_share, :dividend_yield, :dividend_date, :ex_dividend_date, to: :overview
|
9
|
+
end
|
10
|
+
|
11
|
+
def overview
|
12
|
+
@overview ||= Stocksy::AlphaVantage.overview(symbol)
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Stocksy::Asset::Profitability
|
4
|
+
def profitability_summary
|
5
|
+
{
|
6
|
+
"1D" => profitability_ago(1.day),
|
7
|
+
"5D" => profitability_ago(5.days),
|
8
|
+
"1M" => profitability_ago(1.month),
|
9
|
+
"6M" => profitability_ago(6.months),
|
10
|
+
"YTD" => profitability_from(Date.today.beginning_of_year),
|
11
|
+
"1Y" => profitability_ago(1.year),
|
12
|
+
"5Y" => profitability_ago(5.years)
|
13
|
+
}
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def profitability_ago(time_ago)
|
19
|
+
initial_date = time_ago == 1.day ? last_traded_date - 1.day : Date.today - time_ago
|
20
|
+
profitability_from(initial_date)
|
21
|
+
end
|
22
|
+
|
23
|
+
def profitability_from(date)
|
24
|
+
profitability_between(date, last_traded_date)
|
25
|
+
end
|
26
|
+
|
27
|
+
def profitability_between(initial_date, final_date)
|
28
|
+
initial_date = closest_traded_date_from(initial_date)
|
29
|
+
final_date = closest_traded_date_from(final_date)
|
30
|
+
initial_price = time_series_dayly[initial_date.to_s].close.to_f
|
31
|
+
final_price = time_series_dayly[final_date.to_s].close.to_f
|
32
|
+
profitability = ((final_price - initial_price) / initial_price) * 100
|
33
|
+
profitability.round(2)
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/concern"
|
4
|
+
require "active_support/core_ext/module/delegation"
|
5
|
+
require "active_support/core_ext/numeric/time"
|
6
|
+
require "active_support/core_ext/integer/time"
|
7
|
+
|
8
|
+
class Stocksy::Asset
|
9
|
+
include Overview
|
10
|
+
include Profitability
|
11
|
+
|
12
|
+
attr_reader :symbol
|
13
|
+
|
14
|
+
def initialize(symbol)
|
15
|
+
@symbol = symbol
|
16
|
+
end
|
17
|
+
|
18
|
+
def last_traded_date
|
19
|
+
@last_traded_date ||= closest_traded_date_from(Date.today)
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def closest_traded_date_from(date)
|
25
|
+
10.times do |days|
|
26
|
+
next_date = date - days.days
|
27
|
+
return next_date if time_series_dayly[next_date.to_s]
|
28
|
+
end
|
29
|
+
raise Stocksy::Error, "No trading date found in the last 10 days from #{date}"
|
30
|
+
end
|
31
|
+
|
32
|
+
def time_series_dayly
|
33
|
+
@time_series_dayly ||= Stocksy::AlphaVantage.get_time_series_dayly(symbol)
|
34
|
+
end
|
35
|
+
end
|
data/lib/stocksy/cli.rb
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "thor"
|
4
|
+
|
5
|
+
# rubocop:disable Metrics/AbcSize
|
6
|
+
# rubocop:disable Metrics/MethodLength
|
7
|
+
class Stocksy::Cli < Thor
|
8
|
+
package_name "Stocksy"
|
9
|
+
|
10
|
+
desc "show [SYMBOL]", "Overview of an asset by symbol"
|
11
|
+
def show(symbol)
|
12
|
+
asset = Stocksy::Asset.new(symbol)
|
13
|
+
|
14
|
+
if asset.name
|
15
|
+
say "#{asset.name} (#{asset.symbol})"
|
16
|
+
say "#{asset.asset_type} - #{asset.exchange} - #{asset.currency} - #{asset.country}"
|
17
|
+
say "#{asset.sector}, #{asset.industry}"
|
18
|
+
blank_line
|
19
|
+
print_wrapped asset.description
|
20
|
+
blank_line
|
21
|
+
say "Dividend per share: #{asset.dividend_per_share} #{asset.currency}"
|
22
|
+
say "Dividend yield: #{asset.dividend_yield.to_f * 100}%"
|
23
|
+
say "Next dividend date: #{asset.dividend_date}"
|
24
|
+
say "Previous dividend date: #{asset.ex_dividend_date}"
|
25
|
+
else
|
26
|
+
say asset.symbol
|
27
|
+
end
|
28
|
+
blank_line
|
29
|
+
say "Profitabilities until #{asset.last_traded_date}:"
|
30
|
+
asset.profitability_summary.each do |interval, profitability|
|
31
|
+
say "#{interval}: #{profitability}%"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
desc "search [KEYWORDS]", "Search for assets by keywords"
|
36
|
+
def search(keywords)
|
37
|
+
search = Stocksy::Search.new(keywords)
|
38
|
+
print_ordered_options_as_table(search.results, %i[name symbol type region currency])
|
39
|
+
end
|
40
|
+
|
41
|
+
desc "login [API KEY]", "Set AlphaVantage API key"
|
42
|
+
def login(api_key)
|
43
|
+
Stocksy::AlphaVantage::ApiKey.save(api_key)
|
44
|
+
say "API key saved into #{Stocksy::AlphaVantage::ApiKey::FILE_PATH}"
|
45
|
+
end
|
46
|
+
|
47
|
+
desc "logout", "Delete AlphaVantage API key"
|
48
|
+
def logout
|
49
|
+
Stocksy::AlphaVantage::ApiKey.delete
|
50
|
+
say "API key deleted from #{Stocksy::AlphaVantage::ApiKey::FILE_PATH}"
|
51
|
+
end
|
52
|
+
|
53
|
+
desc "version", "Show Stocksy version"
|
54
|
+
def version
|
55
|
+
say Stocksy::VERSION
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def blank_line
|
61
|
+
say "\n"
|
62
|
+
end
|
63
|
+
|
64
|
+
def print_ordered_options_as_table(ordered_options, columns)
|
65
|
+
table_data = [columns.map { |column| column.to_s.gsub("_", " ").capitalize }]
|
66
|
+
ordered_options.each do |option|
|
67
|
+
row = columns.map { |column| option[column] }
|
68
|
+
table_data << row
|
69
|
+
end
|
70
|
+
print_table(table_data)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
# rubocop:enable Metrics/AbcSize
|
74
|
+
# rubocop:enable Metrics/MethodLength
|
data/lib/stocksy.rb
ADDED
metadata
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: stocksy
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Bruno Prieto
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2023-09-02 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activesupport
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: thor
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: zeitwerk
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
description:
|
56
|
+
email:
|
57
|
+
- brunoprietog@hey.com
|
58
|
+
executables:
|
59
|
+
- stocksy
|
60
|
+
extensions: []
|
61
|
+
extra_rdoc_files: []
|
62
|
+
files:
|
63
|
+
- LICENSE.txt
|
64
|
+
- README.md
|
65
|
+
- bin/stocksy
|
66
|
+
- lib/stocksy.rb
|
67
|
+
- lib/stocksy/alpha_vantage.rb
|
68
|
+
- lib/stocksy/alpha_vantage/api_key.rb
|
69
|
+
- lib/stocksy/asset.rb
|
70
|
+
- lib/stocksy/asset/overview.rb
|
71
|
+
- lib/stocksy/asset/profitability.rb
|
72
|
+
- lib/stocksy/cli.rb
|
73
|
+
- lib/stocksy/search.rb
|
74
|
+
- lib/stocksy/version.rb
|
75
|
+
homepage: https://github.com/brunoprietog/stocksy
|
76
|
+
licenses:
|
77
|
+
- MIT
|
78
|
+
metadata:
|
79
|
+
rubygems_mfa_required: 'true'
|
80
|
+
post_install_message:
|
81
|
+
rdoc_options: []
|
82
|
+
require_paths:
|
83
|
+
- lib
|
84
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: 3.2.0
|
89
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
90
|
+
requirements:
|
91
|
+
- - ">="
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
requirements: []
|
95
|
+
rubygems_version: 3.4.15
|
96
|
+
signing_key:
|
97
|
+
specification_version: 4
|
98
|
+
summary: Command line tool to get stock market data
|
99
|
+
test_files: []
|