stockcruncher 1.2.0 → 1.2.1

Sign up to get free protection for your applications and to get access to all the features.
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