stockcruncher 1.2.0 → 1.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7bd12e5a6e5db6f83f239c1b6da9aca85931048dd427778ffb96f043e7334596
4
- data.tar.gz: 48fe8efa593f30fe39c294725d7090c89a4a14413eaa59a1d6741c817fc02d64
3
+ metadata.gz: e4729948dfb9635323240f73d947c2257b1ca4b8a6c2a065a812a8726f502599
4
+ data.tar.gz: 3686ad0bbb61ef2a3801a2a2c1b3258b543da3015c49b2c959570c9d7b0e8a3a
5
5
  SHA512:
6
- metadata.gz: ad4ed352a8ed30d41edbe9c4bac03ba721c9af42837f9e94f9c14df2175013d4ae7a09e29c7076e034cf375abaf222ce04c251a4b8fde31ce10ae29936c18894
7
- data.tar.gz: 06206e1a91e23706c6a83c02357b31064124a21e522f3144d4ec93d4d4e7863e82e38cf4b561eedb662e59ea801120ee05f8cd3fff1b414da5ea5a069dd337ff
6
+ metadata.gz: 24120c82f3e7cd9d622bcf1636ee528ea69d170fe0f60951b33b34754870a1b92837d5f2cbcd3f59ab4be85264195e7c2058036a557e8b486c8fe55cf81e5c18
7
+ data.tar.gz: e849aea61ae75175742d97611cffdc889aa3c95394aec2cc8ccbe93ed35bafc6958984fb0fc92b08190a41003c183b753ad287a51676990eee855d32f43bfceb
data/CHANGELOG CHANGED
@@ -22,3 +22,9 @@ Changelog
22
22
 
23
23
  - daily subcommand now recalculates missing data
24
24
  - daily subcommand also writes data to database
25
+
26
+ 1.2.1
27
+ -----
28
+
29
+ - Refactor to preprocess data in source class
30
+ - Refactor to print pretty json instead of comma separated striing
@@ -8,12 +8,40 @@ module StockCruncher
8
8
  class AlphaVantage < Cruncher
9
9
  API_URL = 'https://www.alphavantage.co/query?'
10
10
 
11
+ # Method to calculate missing data (previousClose, change, changePercent)
12
+ def calculate_missing_data(hash)
13
+ keys = hash.keys
14
+ hash.each_with_index do |(date, v), index|
15
+ prevday = keys[index + 1]
16
+ next if prevday.nil?
17
+
18
+ prevclose = hash[prevday]['close']
19
+ hash[date] = v.merge(generate_missing_data(v['close'], prevclose))
20
+ end
21
+ hash
22
+ end
23
+
24
+ # Method to calculate change difference
25
+ def change(value, base)
26
+ (value - base).round(4).to_s
27
+ end
28
+
29
+ # Method to calculate percentage of change
30
+ def change_percent(value, base)
31
+ ((value / base - 1) * 100).round(4).to_s
32
+ end
33
+
34
+ # Method to create a new hash from two arrays of keys and values
35
+ def create_hash(descriptions, values)
36
+ descriptions.split(',').zip(values.split(',')).to_h
37
+ end
38
+
11
39
  # Main method to crunch data.
12
40
  def crunch_daily(symbol, fullsize)
13
41
  url = API_URL + parameters(symbol, 'TIME_SERIES_DAILY')
14
42
  url += '&datatype=csv&outputsize=' + (fullsize ? 'full' : 'compact')
15
43
  res = request(url)
16
- res.body
44
+ transform_daily(res.body)
17
45
  end
18
46
 
19
47
  # Main method to crunch data.
@@ -21,14 +49,56 @@ module StockCruncher
21
49
  url = API_URL + parameters(symbol, 'GLOBAL_QUOTE')
22
50
  url += '&datatype=csv'
23
51
  res = request(url)
24
- res.body
52
+ transform_quote(res.body)
25
53
  end
26
54
 
55
+ # Method to generate missing data
56
+ def generate_missing_data(current, previous)
57
+ {
58
+ 'previousClose' => previous,
59
+ 'change' => change(current.to_f, previous.to_f),
60
+ 'changePercent' => change_percent(current.to_f, previous.to_f)
61
+ }
62
+ end
63
+
64
+ # Set parameters of api call
27
65
  def parameters(symbol, serie)
28
66
  p = 'function=' + serie
29
67
  p += '&symbol=' + symbol
30
68
  p += '&apikey=' + @config[self.class.name.split('::').last]['apikey']
31
69
  p
32
70
  end
71
+
72
+ # Method to transform raw data to constructed hash
73
+ def prepare_daily_timeserie(data)
74
+ lines = data.split("\r\n")
75
+ desc = lines.shift.split(',').drop(1)
76
+ hash = {}
77
+ lines.each do |line|
78
+ values = line.split(',')
79
+ date = values.shift
80
+ hash[date] = desc.zip(values).to_h
81
+ end
82
+ hash
83
+ end
84
+
85
+ # Method to transform daily result to nested hash
86
+ def transform_daily(rawdata)
87
+ raise StandardError, 'No data' if rawdata.match?(/Error Message/)
88
+
89
+ values = prepare_daily_timeserie(rawdata)
90
+ values = calculate_missing_data(values)
91
+ values
92
+ end
93
+
94
+ # Method to transform quote result to hash
95
+ def transform_quote(rawdata)
96
+ raise StandardError, 'No data' if rawdata.match?(/{}/)
97
+
98
+ values = create_hash(*rawdata.split("\r\n"))
99
+ values['close'] = values.delete('price')
100
+ values['changePercent'] = values['changePercent'].delete('%')
101
+ values
102
+ end
33
103
  end
34
104
  end
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/ruby
2
2
  # frozen_string_literal: true
3
3
 
4
+ require 'json'
4
5
  require 'thor'
5
6
  require 'yaml'
6
7
 
@@ -48,9 +49,9 @@ module StockCruncher
48
49
  opts = options.dup
49
50
  config = YAML.load_file(opts['config'])
50
51
  cruncher = StockCruncher::AlphaVantage.new(config, opts['insecure'])
51
- raw_data = cruncher.crunch_daily(symbol, opts['full'])
52
- StockCruncher::InfluxDB.new(config).export_history(symbol, raw_data)
53
- puts raw_data unless opts['quiet']
52
+ data = cruncher.crunch_daily(symbol, opts['full'])
53
+ StockCruncher::InfluxDB.new(config).export_history(symbol, data)
54
+ puts JSON.pretty_generate(data) unless opts['quiet']
54
55
  end
55
56
 
56
57
  desc('quote SYMBOL [options]',
@@ -59,9 +60,9 @@ module StockCruncher
59
60
  opts = options.dup
60
61
  config = YAML.load_file(opts['config'])
61
62
  cruncher = StockCruncher::AlphaVantage.new(config, opts['insecure'])
62
- raw_data = cruncher.crunch_quote(symbol)
63
- StockCruncher::InfluxDB.new(config).export_last_day(raw_data)
64
- puts raw_data unless opts['quiet']
63
+ data = cruncher.crunch_quote(symbol)
64
+ StockCruncher::InfluxDB.new(config).export_last_day(data)
65
+ puts JSON.pretty_generate(data) unless opts['quiet']
65
66
  end
66
67
  end
67
68
  end
@@ -13,62 +13,16 @@ module StockCruncher
13
13
  @insecure = insecure
14
14
  end
15
15
 
16
- # Method to calculate missing data (previousClose, change, changePercent)
17
- def calculate_missing_data(hash)
18
- keys = hash.keys
19
- hash.each_with_index do |(date, v), index|
20
- prevday = keys[index + 1]
21
- next if prevday.nil?
22
-
23
- prevclose = hash[prevday]['close']
24
- hash[date] = v.merge(generate_missing_data(v['close'], prevclose))
25
- end
26
- hash
27
- end
28
-
29
- # Method to generate missing data
30
- def generate_missing_data(current, previous)
31
- {
32
- 'previousClose' => previous,
33
- 'change' => change(current.to_f, previous.to_f),
34
- 'changePercent' => change_percent(current.to_f, previous.to_f)
35
- }
36
- end
37
-
38
- # Method to calculate change difference
39
- def change(value, base)
40
- (value - base).round(4).to_s
41
- end
42
-
43
- # Method to calculate percentage of change
44
- def change_percent(value, base)
45
- ((value / base - 1) * 100).round(4).to_s
46
- end
47
-
48
- # Method to create a new hash from two arrays of keys and values
49
- def create_hash(descriptions, values)
50
- descriptions.split(',').zip(values.split(',')).to_h
51
- end
52
-
53
16
  # Method to export latest data to database
54
- def export_last_day(raw)
55
- raise StandardError, 'No data to export' if raw.match?(/{}/)
56
-
57
- values = create_hash(*raw.split("\r\n"))
58
- values['close'] = values.delete('price')
59
- values['changePercent'] = values['changePercent'].delete('%')
17
+ def export_last_day(values)
60
18
  tags = { 'symbol' => values.delete('symbol') }
61
19
  date = values.delete('latestDay')
62
20
  write('daily', tags, values, date)
63
21
  end
64
22
 
65
23
  # Method to export historical data to database
66
- def export_history(symbol, raw)
67
- raise StandardError, 'No data to export' if raw.match?(/Error Message/)
68
-
24
+ def export_history(symbol, timeseries)
69
25
  tags = { 'symbol' => symbol }
70
- timeseries = prepare_daily_timeserie(raw)
71
- timeseries = calculate_missing_data(timeseries)
72
26
  timeseries.each_pair do |date, values|
73
27
  write('daily', tags, values, date)
74
28
  end
@@ -84,19 +38,6 @@ module StockCruncher
84
38
  string
85
39
  end
86
40
 
87
- # Method to transform raw data to constructed hash
88
- def prepare_daily_timeserie(data)
89
- lines = data.split("\r\n")
90
- desc = lines.shift.split(',').drop(1)
91
- hash = {}
92
- lines.each do |line|
93
- values = line.split(',')
94
- date = values.shift
95
- hash[date] = desc.zip(values).to_h
96
- end
97
- hash
98
- end
99
-
100
41
  # Method to send http post request
101
42
  def request(url, body)
102
43
  uri = URI.parse(url)
@@ -2,5 +2,5 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module StockCruncher
5
- VERSION = '1.2.0'
5
+ VERSION = '1.2.1'
6
6
  end
@@ -0,0 +1,49 @@
1
+ {
2
+ "2020-08-03": {
3
+ "open": "23.8500",
4
+ "high": "24.6500",
5
+ "low": "23.7400",
6
+ "close": "24.5500",
7
+ "volume": "3112972",
8
+ "previousClose": "23.8100",
9
+ "change": "0.74",
10
+ "changePercent": "3.1079"
11
+ },
12
+ "2020-07-31": {
13
+ "open": "24.0100",
14
+ "high": "24.5100",
15
+ "low": "23.5900",
16
+ "close": "23.8100",
17
+ "volume": "5482485",
18
+ "previousClose": "23.6600",
19
+ "change": "0.15",
20
+ "changePercent": "0.634"
21
+ },
22
+ "2020-07-30": {
23
+ "open": "24.4700",
24
+ "high": "24.6600",
25
+ "low": "23.5200",
26
+ "close": "23.6600",
27
+ "volume": "6466738",
28
+ "previousClose": "24.5600",
29
+ "change": "-0.9",
30
+ "changePercent": "-3.6645"
31
+ },
32
+ "2020-07-29": {
33
+ "open": "24.7500",
34
+ "high": "25.0300",
35
+ "low": "24.0400",
36
+ "close": "24.5600",
37
+ "volume": "4605804",
38
+ "previousClose": "24.7500",
39
+ "change": "-0.19",
40
+ "changePercent": "-0.7677"
41
+ },
42
+ "2020-07-28": {
43
+ "open": "25.9900",
44
+ "high": "26.0700",
45
+ "low": "24.5100",
46
+ "close": "24.7500",
47
+ "volume": "6904261"
48
+ }
49
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "open": "100.0000",
3
+ "high": "100.1000",
4
+ "low": "99.9000",
5
+ "volume": "4",
6
+ "previousClose": "100.0000",
7
+ "change": "0.0000",
8
+ "changePercent": "0.0000",
9
+ "close": "100.0000"
10
+ }
@@ -1,15 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'json'
3
4
  require 'spec_helper'
4
5
 
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
- daily = "timestamp,open,high,low,close,volume\r\n2020-08-03,23.8500,24.6500," \
9
- "23.7400,24.5500,3112972\r\n2020-07-31,24.0100,24.5100,23.5900,23.81" \
10
- "00,5482485\r\n2020-07-30,24.4700,24.6600,23.5200,23.6600,6466738\r" \
11
- "\n2020-07-29,24.7500,25.0300,24.0400,24.5600,4605804\r\n2020-07-28," \
12
- "25.9900,26.0700,24.5100,24.7500,6904261\r\n"
6
+ daily = File.read('spec/files/SYM.daily')
7
+ quote = File.read('spec/files/SYM.quote')
13
8
 
14
9
  describe StockCruncher::CLI do # rubocop:disable Metrics/BlockLength
15
10
  context 'version' do
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.2.0
4
+ version: 1.2.1
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-08-04 00:00:00.000000000 Z
11
+ date: 2020-08-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -132,6 +132,8 @@ files:
132
132
  - lib/stockcruncher/cruncher.rb
133
133
  - lib/stockcruncher/influxdb.rb
134
134
  - lib/stockcruncher/version.rb
135
+ - spec/files/SYM.daily
136
+ - spec/files/SYM.quote
135
137
  - spec/files/stockcruncher.yml
136
138
  - spec/spec_helper.rb
137
139
  - spec/stockcruncher/cli_spec.rb