stockcruncher 1.0.2 → 1.1.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c1fe544c0ab3e0bb05c2cca11cb4363bce698cf88b565d897098420b3b8206ac
4
- data.tar.gz: bc0de76838cf286f9c5400ddc368da33ee2bd748f0a5a29ebed653010e183d8a
3
+ metadata.gz: 51887b6440cf8d3958f52c05d5daa9e77c0bada0e385445ec6bcb6553fe9c16d
4
+ data.tar.gz: 66ade1c3623130c5e5588ceca005bddb201b176d1d81ffbb0cabd41568b1692c
5
5
  SHA512:
6
- metadata.gz: b69c6d91c2160e1e70a339ea68616b27012839b105dcfd0cef5ccf7a9643e3a08fb88738d794cf98e3d4de03e505c32db4a827d45a296d734f7e10d2334eb287
7
- data.tar.gz: 44ecc54323e85117c04bb0aa8b9c2ab54421020a2614b01356988700f610264e1e82a07e88d5fd62f62945c1469c508699b3a78c2dad52a73b988e508ce2264d
6
+ metadata.gz: 0bbdd83e653eadf37c57b6cf5e2bf3234c94ccf74d59ffcd21f995d74260a7673da8a79564f37b4b69715fb5f295d0e1bcf2465fee119a84965cbcc333d0f0bc
7
+ data.tar.gz: 979223a1ee0cba78f9d482d22f3025c17fb0506c487d237b94b5855a7843ef3eca610fd89fcbd0a41c66325a1f9e86786e0b56703d666fbca8d5417dd3906321
data/CHANGELOG CHANGED
@@ -5,3 +5,9 @@ Changelog
5
5
  -----
6
6
 
7
7
  - Initial version
8
+
9
+ 1.1.0
10
+ -----
11
+
12
+ - Add InfluxDB as database.
13
+ - WIP for daily time serie.
data/README.md CHANGED
@@ -25,29 +25,38 @@ to write the data in a database for later calculation and use.
25
25
 
26
26
  $ gem install stockcruncher
27
27
  $ mkdir /etc/stockcruncher && cd /etc/stockcruncher
28
- $ echo $'AlphaVantage:\n apikey: CHANGEME' > stockcruncher.yml
28
+ $ echo 'AlphaVantage:' > stockcruncher.yml
29
+ $ echo ' apikey: CHANGEME' >> stockcruncher.yml
30
+ $ echo 'InfluxDB:' >> stockcruncher.yml
31
+ $ echo ' scheme: http' >> stockcruncher.yml
32
+ $ echo ' host: localhost' >> stockcruncher.yml
33
+ $ echo ' port: 8086' >> stockcruncher.yml
34
+ $ echo ' user: CHANGEMEAGAIN' >> stockcruncher.yml
35
+ $ echo ' password: CHANGEMETOO' >> stockcruncher.yml
36
+ $ echo ' dbname: stock' >> stockcruncher.yml
29
37
 
30
38
  ## Usage
31
39
 
32
40
  An interactive help is available with:
33
41
 
34
- $ stockcruncher help
42
+ $ stockcruncher help [subcommand]
35
43
 
36
44
  ## Examples
37
45
 
38
46
  To get daily time serie data of a symbol:
39
47
 
40
- $ stockcruncher crunch AAPL daily
48
+ $ stockcruncher daily AAPL
41
49
 
42
50
  To get last day endpoint data of a symbol:
43
51
 
44
- $ stockcruncher crunch AAPL quote_endpoint
52
+ $ stockcruncher quote AAPL
45
53
 
46
54
  ## Limitations
47
55
 
48
56
  Data are currently scraped from AlphaVantage API.
49
57
  More source could be great especially because AlphaVantage doesn't provide EU
50
58
  intraday data.
59
+ InfluxDB is used as database to keep time series data.
51
60
 
52
61
  ## Development
53
62
 
@@ -9,28 +9,19 @@ module StockCruncher
9
9
  API_URL = 'https://www.alphavantage.co/query?'
10
10
 
11
11
  # Main method to crunch data.
12
- def crunch_daily(symbol, opts)
13
- url = API_URL + parameters(symbol, 'TIME_SERIES_DAILY') + options_d(opts)
12
+ def crunch_daily(symbol, fullsize)
13
+ url = API_URL + parameters(symbol, 'TIME_SERIES_DAILY')
14
+ url += '&datatype=csv&outputsize=' + (fullsize ? 'full' : 'compact')
14
15
  res = request(url)
15
- puts res.body
16
+ res.body
16
17
  end
17
18
 
18
19
  # Main method to crunch data.
19
- def crunch_quote(symbol, opts)
20
- url = API_URL + parameters(symbol, 'GLOBAL_QUOTE') + options_q(opts)
20
+ def crunch_quote(symbol)
21
+ url = API_URL + parameters(symbol, 'GLOBAL_QUOTE')
22
+ url += '&datatype=csv'
21
23
  res = request(url)
22
- puts res.body
23
- end
24
-
25
- def options_d(opts)
26
- o = '&datatype=' + (opts['json'] ? 'json' : 'csv')
27
- o += '&outputsize=' + (opts['full'] ? 'full' : 'compact')
28
- o
29
- end
30
-
31
- def options_q(opts)
32
- o = '&datatype=' + (opts['json'] ? 'json' : 'csv')
33
- o
24
+ res.body
34
25
  end
35
26
 
36
27
  def parameters(symbol, serie)
@@ -2,18 +2,12 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require 'thor'
5
+ require 'yaml'
5
6
 
6
7
  module StockCruncher
7
8
  # Simple CLI for StockCruncher
8
9
  class CLI < Thor
9
- desc 'version', 'Print stockcruncher current version'
10
- def version
11
- puts "StockCruncher version #{StockCruncher::VERSION}"
12
- end
13
-
14
- desc('daily SYMBOL [options]',
15
- 'Crunch SYMBOL stock market data for daily time series.')
16
- option(
10
+ class_option(
17
11
  :config,
18
12
  aliases: ['-c'],
19
13
  type: :string,
@@ -21,13 +15,28 @@ module StockCruncher
21
15
  desc: 'Yaml formatted config file to load ' \
22
16
  '(default to /etc/stockcruncher/stockcruncher.yml).'
23
17
  )
24
- option(
25
- :json,
26
- aliases: ['-j'],
18
+ class_option(
19
+ :insecure,
20
+ aliases: ['-k'],
21
+ type: :boolean,
22
+ default: false,
23
+ desc: 'Ignore SSL certificate (default to false).'
24
+ )
25
+ class_option(
26
+ :quiet,
27
+ aliases: ['-q'],
27
28
  type: :boolean,
28
29
  default: false,
29
- desc: 'Json format data (default to csv).'
30
+ desc: 'Run silently (default to false).'
30
31
  )
32
+
33
+ desc 'version', 'Print stockcruncher current version'
34
+ def version
35
+ puts "StockCruncher version #{StockCruncher::VERSION}"
36
+ end
37
+
38
+ desc('daily SYMBOL [options]',
39
+ 'Crunch SYMBOL stock market data for daily time series.')
31
40
  option(
32
41
  :full,
33
42
  aliases: ['-f'],
@@ -37,31 +46,22 @@ module StockCruncher
37
46
  )
38
47
  def daily(symbol)
39
48
  opts = options.dup
40
- cruncher = StockCruncher::AlphaVantage.new(opts['config'])
41
- cruncher.crunch_daily(symbol, opts)
49
+ config = YAML.load_file(opts['config'])
50
+ cruncher = StockCruncher::AlphaVantage.new(config, opts['insecure'])
51
+ raw_data = cruncher.crunch_daily(symbol, opts['full'])
52
+ # TODO: export to DB here
53
+ puts raw_data unless opts['quiet']
42
54
  end
43
55
 
44
56
  desc('quote SYMBOL [options]',
45
57
  'Crunch SYMBOL stock market data for last day quote.')
46
- option(
47
- :config,
48
- aliases: ['-c'],
49
- type: :string,
50
- default: '/etc/stockcruncher/stockcruncher.yml',
51
- desc: 'Yaml formatted config file to load ' \
52
- '(default to /etc/stockcruncher/stockcruncher.yml).'
53
- )
54
- option(
55
- :json,
56
- aliases: ['-j'],
57
- type: :boolean,
58
- default: false,
59
- desc: 'Json format data (default to csv).'
60
- )
61
58
  def quote(symbol)
62
59
  opts = options.dup
63
- cruncher = StockCruncher::AlphaVantage.new(opts['config'])
64
- cruncher.crunch_quote(symbol, opts)
60
+ config = YAML.load_file(opts['config'])
61
+ cruncher = StockCruncher::AlphaVantage.new(config, opts['insecure'])
62
+ raw_data = cruncher.crunch_quote(symbol)
63
+ puts raw_data unless opts['quiet']
64
+ StockCruncher::InfluxDB.new(config).export_last_day(raw_data)
65
65
  end
66
66
  end
67
67
  end
@@ -2,27 +2,22 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require 'net/http'
5
- require 'yaml'
6
5
 
7
6
  module StockCruncher
8
7
  # This is an data cruncher abstract class.
9
8
  class Cruncher
10
9
  # Class constructor method
11
- def initialize(file)
12
- @config = load_conf(file)
13
- end
14
-
15
- # Method to load configurations described in config_file.
16
- def load_conf(file)
17
- YAML.load_file(file)
10
+ def initialize(config, insecure = false)
11
+ @config = config
12
+ @insecure = insecure
18
13
  end
19
14
 
20
15
  # Method to send http get request
21
- def request(url, insecure = false)
16
+ def request(url)
22
17
  uri = URI.parse(url)
23
18
  http = Net::HTTP.new(uri.host, uri.port)
24
19
  http.use_ssl = uri.scheme.eql?('https')
25
- http.verify_mode = OpenSSL::SSL::VERIFY_NONE if insecure
20
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE if @insecure
26
21
  req = Net::HTTP::Get.new(uri.request_uri)
27
22
  http.request(req)
28
23
  end
@@ -0,0 +1,63 @@
1
+ #!/usr/bin/ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'net/http'
5
+
6
+ module StockCruncher
7
+ # this is a class to write time series to database
8
+ class InfluxDB
9
+ # Class constructor method
10
+ def initialize(config, insecure = false)
11
+ @cfg = config[self.class.name.split('::').last]
12
+ @insecure = insecure
13
+ end
14
+
15
+ # Method to export latest data to database
16
+ def export_last_day(raw)
17
+ (desc, line) = raw.split("\r\n")
18
+ values = desc.split(',').zip(line.split(',')).to_h
19
+ values['close'] = values.delete('price')
20
+ values['changePercent'] = values['changePercent'].delete('%')
21
+ tags = { 'symbol' => values.delete('symbol') }
22
+ date = values.delete('latestDay')
23
+ write('daily', tags, values, date)
24
+ end
25
+
26
+ # Method to export historical data to database
27
+ def export_history(raw)
28
+ # TODO: export whole history and calculated missing values
29
+ end
30
+
31
+ # Method to format and array of values into comma separated string
32
+ def format_values(values)
33
+ string = ''
34
+ values.each_pair do |k, v|
35
+ string += "#{k}=#{v}"
36
+ string += ',' unless k == values.keys.last
37
+ end
38
+ string
39
+ end
40
+
41
+ # Method to send http post request
42
+ def request(url, body)
43
+ uri = URI.parse(url)
44
+ http = Net::HTTP.new(uri.host, uri.port)
45
+ http.use_ssl = uri.scheme.eql?('https')
46
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE if @insecure
47
+ req = Net::HTTP::Post.new(uri.request_uri)
48
+ req.basic_auth(@cfg['user'], @cfg['password'])
49
+ req.body = body
50
+ http.request(req)
51
+ end
52
+
53
+ # Method to write data in bucket
54
+ def write(name, tags, values, date)
55
+ url = "#{@cfg['scheme']}://#{@cfg['host']}:#{@cfg['port']}/write?" \
56
+ "db=#{@cfg['dbname']}"
57
+ timestamp = DateTime.parse(date + 'T18:00:00').strftime('%s%N')
58
+ body = "#{name},#{format_values(tags)} #{format_values(values)} " \
59
+ "#{timestamp}"
60
+ request(url, body)
61
+ end
62
+ end
63
+ end
@@ -2,5 +2,5 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module StockCruncher
5
- VERSION = '1.0.2'
5
+ VERSION = '1.1.0'
6
6
  end
@@ -1,2 +1,9 @@
1
1
  AlphaVantage:
2
2
  apikey: demo
3
+ InfluxDB:
4
+ scheme: http
5
+ host: localhost
6
+ port: 8086
7
+ user: testuser
8
+ password: testpassword
9
+ dbname: test
@@ -2,6 +2,10 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
+ quote = 'symbol,open,high,low,price,volume,latestDay,previousClose,change,ch' \
6
+ "angePercent\r\nSYM,100.0000,100.1000,99.9000,100.0000,4,2020-07-30," \
7
+ "100.0000,0.0000,0.0000%\r\n"
8
+
5
9
  describe StockCruncher::CLI do
6
10
  context 'version' do
7
11
  it 'prints the version.' do
@@ -18,7 +22,7 @@ describe StockCruncher::CLI do
18
22
 
19
23
  context 'quote SYM -c spec/files/stockcruncher.yml' do
20
24
  it 'Get the quote for SYM.' do
21
- expect { start(self) }.to output("{}\n").to_stdout
25
+ expect { start(self) }.to output(quote).to_stdout
22
26
  end
23
27
  end
24
28
 
@@ -2,15 +2,21 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
+ quote = 'symbol,open,high,low,price,volume,latestDay,previousClose,change,ch' \
6
+ "angePercent\r\nSYM,100.0000,100.1000,99.9000,100.0000,4,2020-07-30," \
7
+ "100.0000,0.0000,0.0000%\r\n"
8
+
5
9
  RSpec.configure do |config|
6
10
  config.before(:each) do
7
11
  # requests an API without extra arguments
8
12
  stub_request(:get, 'https://www.alphavantage.co/query?' \
9
13
  'function=GLOBAL_QUOTE&symbol=SYM&apikey=demo&datatype=csv')
10
- .to_return('status' => 200, 'body' => '{}', 'headers' => {})
14
+ .to_return('status' => 200, 'body' => quote, 'headers' => {})
11
15
  stub_request(:get, 'https://www.alphavantage.co/query?' \
12
16
  'function=TIME_SERIES_DAILY&symbol=SYM&apikey=demo' \
13
17
  '&datatype=csv&outputsize=compact')
14
18
  .to_return('status' => 200, 'body' => '{}', 'headers' => {})
19
+ stub_request(:post, 'http://localhost:8086/write?db=test')
20
+ .to_return('status' => 204, 'body' => '', 'headers' => {})
15
21
  end
16
22
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stockcruncher
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.2
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Richard Delaplace
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-07-30 00:00:00.000000000 Z
11
+ date: 2020-07-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -130,10 +130,10 @@ files:
130
130
  - lib/stockcruncher/alphavantage.rb
131
131
  - lib/stockcruncher/cli.rb
132
132
  - lib/stockcruncher/cruncher.rb
133
+ - lib/stockcruncher/influxdb.rb
133
134
  - lib/stockcruncher/version.rb
134
135
  - spec/files/stockcruncher.yml
135
136
  - spec/spec_helper.rb
136
- - spec/stockcruncher/alphavantage_spec.rb
137
137
  - spec/stockcruncher/cli_spec.rb
138
138
  - spec/stockcruncher/stubs/servers_stubs.rb
139
139
  - spec/stockcruncher_spec.rb
@@ -1,16 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'spec_helper'
4
-
5
- describe StockCruncher::AlphaVantage do
6
- context 'daily SYM -c spec/files/stockcruncher.yml' do
7
- it 'requests a daily time serie.' do
8
- expect { start(self) }.to output("{}\n").to_stdout
9
- end
10
- end
11
- context 'quote SYM -c spec/files/stockcruncher.yml' do
12
- it 'requests a quote endpoint.' do
13
- expect { start(self) }.to output("{}\n").to_stdout
14
- end
15
- end
16
- end