stockcruncher 1.2.0 → 1.3.2

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: 56cbc10941fcfdc6ccee0273cf5b2f43f4a98c1f3b53b1554a53ea45020c604e
4
+ data.tar.gz: ce451b4498697f9c6148167771296219c4f83ffdef3f1fbefb4c8a12f7a747e4
5
5
  SHA512:
6
- metadata.gz: ad4ed352a8ed30d41edbe9c4bac03ba721c9af42837f9e94f9c14df2175013d4ae7a09e29c7076e034cf375abaf222ce04c251a4b8fde31ce10ae29936c18894
7
- data.tar.gz: 06206e1a91e23706c6a83c02357b31064124a21e522f3144d4ec93d4d4e7863e82e38cf4b561eedb662e59ea801120ee05f8cd3fff1b414da5ea5a069dd337ff
6
+ metadata.gz: 5b3bcfdbe1805e95c4729e33ad26b4ea676d63a5e638150fca0a26d75682a96d6d4d71a16e9458ef75423f82fc4ba0a4f7442e838865ac9d27b57fbb817dbaed
7
+ data.tar.gz: fbe77bb52c0b0d51d6f480246c9467ca4838f9afd385e573c35342b40ada8973f0f5f52c65d159ae85f332d8e0a38e244cf5149b386dc10872323d5990726451
data/.gitlab-ci.yml CHANGED
@@ -1,9 +1,11 @@
1
+
1
2
  image: ruby:2.4
2
3
 
4
+ before_script:
5
+ - bundle install
6
+
3
7
  rubocop:
4
8
  stage: test
5
- before_script:
6
- - gem install --silent rubocop
7
9
  script:
8
10
  - rubocop
9
11
 
@@ -25,7 +27,6 @@ git_history:
25
27
  rspec:
26
28
  stage: test
27
29
  script:
28
- - bundle install
29
30
  - rspec
30
31
  artifacts:
31
32
  paths:
data/.rubocop.yml CHANGED
@@ -4,3 +4,4 @@ AllCops:
4
4
  DisplayStyleGuide: true
5
5
  DisplayCopNames: false
6
6
  TargetRubyVersion: 2.4
7
+ NewCops: disable
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
data/README.md CHANGED
@@ -5,12 +5,14 @@
5
5
  [![Gem Version][gem-img]][gem]
6
6
 
7
7
  1. [Overview](#overview)
8
- 2. [Description](#role-description)
9
- 3. [Setup](#setup)
10
- 4. [Usage](#usage)
11
- 5. [Limitations](#limitations)
12
- 6. [Development](#development)
13
- 7. [Miscellaneous](#miscellaneous)
8
+ 1. [Description](#description)
9
+ 1. [Setup](#setup)
10
+ 1. [Usage](#usage)
11
+ 1. [Environment variables](#environment-variables)
12
+ 1. [Examples](#examples)
13
+ 1. [Limitations](#limitations)
14
+ 1. [Development](#development)
15
+ 1. [Miscellaneous](#miscellaneous)
14
16
 
15
17
  ## Overview
16
18
 
@@ -41,6 +43,17 @@ An interactive help is available with:
41
43
 
42
44
  $ stockcruncher help [subcommand]
43
45
 
46
+ ## Environment variables
47
+
48
+ Parameters in /etc/stockcruncher/stockcrunucher.yml can be overloaded with
49
+ environment variables.
50
+ Environment variables should match SCR_<COMPONENTID>_<ITEM>.
51
+ Component ID are as follow.
52
+ - AlphaVantage: AV
53
+ - InfluxDB: IDB
54
+ Items are upcase keys. See template /etc/stockcruncher/stockcrunucher.yml for
55
+ reference.
56
+
44
57
  ## Examples
45
58
 
46
59
  To get daily time serie data of a symbol:
@@ -51,6 +64,10 @@ To get last day endpoint data of a symbol:
51
64
 
52
65
  $ stockcruncher quote AAPL
53
66
 
67
+ To override a parameter with environment variable:
68
+
69
+ $ SCR_IDB_HOST=192.168.0.80; stockcruncher quote AAPL
70
+
54
71
  ## Limitations
55
72
 
56
73
  Data are currently scraped from AlphaVantage API.
@@ -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
- url += '&datatype=csv&outputsize=' + (fullsize ? 'full' : 'compact')
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,55 @@ 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
- p = 'function=' + serie
29
- p += '&symbol=' + symbol
30
- p += '&apikey=' + @config[self.class.name.split('::').last]['apikey']
66
+ p = "function=#{serie}"
67
+ p += "&symbol=#{symbol}"
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
+ calculate_missing_data(values)
91
+ end
92
+
93
+ # Method to transform quote result to hash
94
+ def transform_quote(rawdata)
95
+ raise StandardError, 'No data' if rawdata.match?(/{}/)
96
+
97
+ values = create_hash(*rawdata.split("\r\n"))
98
+ values['close'] = values.delete('price')
99
+ values['changePercent'] = values['changePercent'].delete('%')
100
+ values
101
+ end
33
102
  end
34
103
  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,20 +49,35 @@ 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']
55
+ end
56
+
57
+ desc('movingaverages SYMBOL [options]',
58
+ 'Calculate and export moving averages for requested symbol.')
59
+ option(
60
+ :all,
61
+ aliases: ['-a'],
62
+ type: :boolean,
63
+ default: false,
64
+ desc: 'Recalculate all MA historical values.'
65
+ )
66
+ def movingaverages(symbol)
67
+ opts = options.dup
68
+ config = YAML.load_file(opts['config'])
69
+ StockCruncher::InfluxDB.new(config).moving_averages(symbol, opts['all'])
54
70
  end
55
71
 
56
72
  desc('quote SYMBOL [options]',
57
73
  'Crunch SYMBOL stock market data for last day quote.')
58
74
  def quote(symbol)
59
75
  opts = options.dup
60
- config = YAML.load_file(opts['config'])
76
+ config = StockCruncher::Config.load(opts['config'])
61
77
  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']
78
+ data = cruncher.crunch_quote(symbol)
79
+ StockCruncher::InfluxDB.new(config).export_last_day(data)
80
+ puts JSON.pretty_generate(data) unless opts['quiet']
65
81
  end
66
82
  end
67
83
  end
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'yaml'
5
+
6
+ module StockCruncher
7
+ # this is a module to load configuration file and environment variable
8
+ module Config
9
+ module_function
10
+
11
+ # Load config file and override with env variables
12
+ def load(file)
13
+ config = YAML.load_file(file)
14
+ overload_alphavantage(config)
15
+ overload_influxdb(config)
16
+ end
17
+
18
+ def overload(config, prefix, component, items)
19
+ items.each do |key|
20
+ var = "#{prefix}#{key.upcase}"
21
+ config[component][key] = ENV[var] unless ENV[var].nil?
22
+ end
23
+ config
24
+ end
25
+
26
+ def overload_alphavantage(config)
27
+ prefix = 'SCR_AV_'
28
+ component = 'AlphaVantage'
29
+ items = %w[apikey]
30
+ overload(config, prefix, component, items)
31
+ end
32
+
33
+ def overload_influxdb(config)
34
+ prefix = 'SCR_IDB_'
35
+ component = 'InfluxDB'
36
+ items = %w[scheme host port user password dbname]
37
+ overload(config, prefix, component, items)
38
+ end
39
+ end
40
+ end
@@ -2,6 +2,7 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require 'date'
5
+ require 'json'
5
6
  require 'net/http'
6
7
 
7
8
  module StockCruncher
@@ -13,88 +14,69 @@ module StockCruncher
13
14
  @insecure = insecure
14
15
  end
15
16
 
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
- }
17
+ def get_daily_values(symbol, fullsize)
18
+ values = %w[close change changePercent volume]
19
+ data = query('daily', symbol, values, fullsize)
20
+ data['columns'].zip(data['values'].transpose).to_h
36
21
  end
37
22
 
38
- # Method to calculate change difference
39
- def change(value, base)
40
- (value - base).round(4).to_s
23
+ # Method to calculate moving averages based on last day values
24
+ def moving_averages(symbol, fullsize)
25
+ series = get_daily_values(symbol, fullsize)
26
+ tags = create_tags(symbol)
27
+ series['close'].each_index do |i|
28
+ date = series['time'][i]
29
+ serie = series['close'][i, 201]
30
+ weights = series['volume'][i, 201]
31
+ write_moving_averages(tags, serie, weights, date)
32
+ break unless fullsize
33
+ end
41
34
  end
42
35
 
43
- # Method to calculate percentage of change
44
- def change_percent(value, base)
45
- ((value / base - 1) * 100).round(4).to_s
36
+ # Method to create tags hash containing only symbol
37
+ def create_tags(symbol)
38
+ { 'symbol' => symbol }
46
39
  end
47
40
 
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
41
+ # Method to export historical data to database
42
+ def export_history(symbol, timeseries)
43
+ tags = create_tags(symbol)
44
+ timeseries.each_pair do |date, values|
45
+ write('daily', tags, values, date)
46
+ end
51
47
  end
52
48
 
53
49
  # 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('%')
60
- tags = { 'symbol' => values.delete('symbol') }
50
+ def export_last_day(values)
51
+ tags = create_tags(values.delete('symbol'))
61
52
  date = values.delete('latestDay')
62
53
  write('daily', tags, values, date)
63
54
  end
64
55
 
65
- # 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
-
69
- tags = { 'symbol' => symbol }
70
- timeseries = prepare_daily_timeserie(raw)
71
- timeseries = calculate_missing_data(timeseries)
72
- timeseries.each_pair do |date, values|
73
- write('daily', tags, values, date)
74
- end
75
- end
76
-
77
56
  # Method to format and array of values into comma separated string
78
57
  def format_values(values)
79
- string = ''
80
- values.each_pair do |k, v|
81
- string += "#{k}=#{v}"
82
- string += ',' unless k == values.keys.last
83
- end
84
- string
58
+ values.map { |k, v| "#{k}=#{v}" }.join(',')
85
59
  end
86
60
 
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
61
+ # Method to calculate all statistics
62
+ def write_moving_averages(tags, serie, weights, date)
63
+ write('ema', tags, StockCruncher::Stats.list_ema(serie), date)
64
+ write('lwma', tags, StockCruncher::Stats.list_lwma(serie), date)
65
+ write('sma', tags, StockCruncher::Stats.list_sma(serie), date)
66
+ write('vwma', tags, StockCruncher::Stats.list_vwma(serie, weights), date)
67
+ end
68
+
69
+ # Method to query data in bucket
70
+ def query(name, symbol, values, full)
71
+ url = "#{@cfg['scheme']}://#{@cfg['host']}:#{@cfg['port']}/query?" \
72
+ "db=#{@cfg['dbname']}"
73
+ size = full ? '' : 'LIMIT 201'
74
+ body = "q=SELECT #{values.join(',')} FROM #{name} " \
75
+ "WHERE symbol = '#{symbol}' ORDER BY time DESC #{size}"
76
+ data = JSON.parse(request(url, body).body)['results'][0]['series']
77
+ raise StandardError, 'No data' if data.nil?
78
+
79
+ data[0]
98
80
  end
99
81
 
100
82
  # Method to send http post request
@@ -113,7 +95,7 @@ module StockCruncher
113
95
  def write(name, tags, values, date)
114
96
  url = "#{@cfg['scheme']}://#{@cfg['host']}:#{@cfg['port']}/write?" \
115
97
  "db=#{@cfg['dbname']}"
116
- timestamp = DateTime.parse(date + 'T18:00:00').strftime('%s%N')
98
+ timestamp = DateTime.parse("#{date}T18:00:00").strftime('%s%N')
117
99
  body = "#{name},#{format_values(tags)} #{format_values(values)} " \
118
100
  "#{timestamp}"
119
101
  request(url, body)
@@ -0,0 +1,74 @@
1
+ #!/usr/bin/ruby
2
+ # frozen_string_literal: true
3
+
4
+ module StockCruncher
5
+ # this is a module with various statistic calculation methods
6
+ module Stats
7
+ extend self
8
+
9
+ RANGES = [5, 10, 20, 30, 50, 100, 200].freeze
10
+
11
+ # Calculate multiple range of exponential moving average
12
+ def list_ema(values)
13
+ h = {}
14
+ RANGES.each do |n|
15
+ next if values.size < n + 1
16
+
17
+ h["ema#{n}"] = ema(values[0, n + 1])
18
+ end
19
+ h
20
+ end
21
+
22
+ # Calculate multiple range of linearly weighted moving average
23
+ def list_lwma(values)
24
+ h = {}
25
+ RANGES.each do |n|
26
+ next if values.size < n
27
+
28
+ weights = (1..n).to_a.reverse
29
+ h["lwma#{n}"] = sma(values[0, n], weights)
30
+ end
31
+ h
32
+ end
33
+
34
+ # Calculate multiple range of simple moving average
35
+ def list_sma(values)
36
+ h = {}
37
+ RANGES.each do |n|
38
+ next if values.size < n
39
+
40
+ h["sma#{n}"] = sma(values[0, n])
41
+ end
42
+ h
43
+ end
44
+
45
+ # Calculate multiple range of volume weighted moving average
46
+ def list_vwma(values, volumes)
47
+ h = {}
48
+ RANGES.each do |n|
49
+ next if values.size < n
50
+
51
+ h["vwma#{n}"] = sma(values[0, n], volumes[0, n])
52
+ end
53
+ h
54
+ end
55
+
56
+ private
57
+
58
+ # Calculate exponential moving average
59
+ def ema(array, factor = 2, weights = nil)
60
+ f = factor.to_f / array.size
61
+ n = array.size - 1
62
+ tsma = sma(array[0, n], weights)
63
+ ysma = sma(array[1, n], weights)
64
+ (tsma * f + ysma * (1 - f)).round(4)
65
+ end
66
+
67
+ # Calculate simple moving average
68
+ def sma(array, weights = nil)
69
+ factor = weights.nil? ? Array.new(array.size, 1) : weights
70
+ dividend = array.each_with_index.map { |v, i| v * factor[i] }
71
+ (dividend.sum.to_f / factor.sum).round(4)
72
+ end
73
+ end
74
+ end
@@ -2,5 +2,5 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module StockCruncher
5
- VERSION = '1.2.0'
5
+ VERSION = '1.3.2'
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
@@ -31,6 +26,12 @@ describe StockCruncher::CLI do # rubocop:disable Metrics/BlockLength
31
26
  end
32
27
  end
33
28
 
29
+ context 'movingaverages SYM -c spec/files/stockcruncher.yml' do
30
+ it 'Get the daily time serie for SYM.' do
31
+ expect { start(self) }.to output('').to_stdout
32
+ end
33
+ end
34
+
34
35
  context 'quote NODATA -c spec/files/stockcruncher.yml' do
35
36
  it 'Should not get any data and should fail.' do
36
37
  expect { start(self) }.to raise_error(SystemExit)
@@ -12,6 +12,11 @@ daily = "timestamp,open,high,low,close,volume\r\n2020-08-03,23.8500,24.6500," \
12
12
  "\n2020-07-29,24.7500,25.0300,24.0400,24.5600,4605804\r\n2020-07-28," \
13
13
  "25.9900,26.0700,24.5100,24.7500,6904261\r\n"
14
14
  d_err = "{\n \"Error Message\": \"Invalid API call.\"\n}"
15
+ mvavg = '{"results":[{"statement_id":0,"series":[{"name":"daily","columns":[' \
16
+ '"time","close","change","changePercent","volume"],"values":[["2017-' \
17
+ '03-01T18:00:00Z",1,0,0,1],["2017-03-02T18:00:00Z",1,0,0,1],["2017-0' \
18
+ '3-03T18:00:00Z",1,0,0,1],["2017-03-04T18:00:00Z",1,0,0,1],["2017-03' \
19
+ '-05T18:00:00Z",1,0,0,1],["2017-03-06T18:00:00Z",1,0,0,1]]}]}]}'
15
20
 
16
21
  RSpec.configure do |config|
17
22
  config.before(:each) do
@@ -30,6 +35,8 @@ RSpec.configure do |config|
30
35
  'function=TIME_SERIES_DAILY&symbol=SYM&apikey=demo' \
31
36
  '&datatype=csv&outputsize=compact')
32
37
  .to_return('status' => 200, 'body' => daily, 'headers' => {})
38
+ stub_request(:post, 'http://localhost:8086/query?db=test')
39
+ .to_return('status' => 204, 'body' => mvavg, 'headers' => {})
33
40
  stub_request(:post, 'http://localhost:8086/write?db=test')
34
41
  .to_return('status' => 204, 'body' => '', 'headers' => {})
35
42
  end
@@ -8,7 +8,7 @@ dev_deps = {
8
8
  'bundler' => '~> 1.17',
9
9
  'rspec' => '~> 3.9',
10
10
  'rake' => '~> 11.3',
11
- 'rubocop' => '0.88',
11
+ 'rubocop' => '0.90',
12
12
  'webmock' => '~> 2.0.3',
13
13
  'simplecov' => '~> 0.18'
14
14
  }
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.3.2
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: 2021-07-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -58,14 +58,14 @@ dependencies:
58
58
  requirements:
59
59
  - - '='
60
60
  - !ruby/object:Gem::Version
61
- version: '0.88'
61
+ version: '0.90'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - '='
67
67
  - !ruby/object:Gem::Version
68
- version: '0.88'
68
+ version: '0.90'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: webmock
71
71
  requirement: !ruby/object:Gem::Requirement
@@ -129,9 +129,13 @@ files:
129
129
  - lib/stockcruncher.rb
130
130
  - lib/stockcruncher/alphavantage.rb
131
131
  - lib/stockcruncher/cli.rb
132
+ - lib/stockcruncher/config.rb
132
133
  - lib/stockcruncher/cruncher.rb
133
134
  - lib/stockcruncher/influxdb.rb
135
+ - lib/stockcruncher/stats.rb
134
136
  - lib/stockcruncher/version.rb
137
+ - spec/files/SYM.daily
138
+ - spec/files/SYM.quote
135
139
  - spec/files/stockcruncher.yml
136
140
  - spec/spec_helper.rb
137
141
  - spec/stockcruncher/cli_spec.rb