stockcruncher 1.1.1 → 1.2.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: 1beb20ef59441b6227bd56d52cb1db85970c50be5cb909d3f631a97539897602
4
- data.tar.gz: 96722ce534f031f40435958d4068a6212b0d4dd583840077423132d7b7349654
3
+ metadata.gz: 7bd12e5a6e5db6f83f239c1b6da9aca85931048dd427778ffb96f043e7334596
4
+ data.tar.gz: 48fe8efa593f30fe39c294725d7090c89a4a14413eaa59a1d6741c817fc02d64
5
5
  SHA512:
6
- metadata.gz: 45ff2b03c7d1233717dd60a4030d376a56ac5eb59d01c89dd6600b77b886cabc79a250686c013ed74463bd4c357a056b75684395bf3bb66b89d2b3c49aeb04f7
7
- data.tar.gz: c7945f2f156aae5f7140165bbeda8794ea9b8f72b56bd810e110ce93ebe0ce21f80cab80b516bcd9c73c4dcbeca6d6bd023581b57a01deff682b922c56a4aa55
6
+ metadata.gz: ad4ed352a8ed30d41edbe9c4bac03ba721c9af42837f9e94f9c14df2175013d4ae7a09e29c7076e034cf375abaf222ce04c251a4b8fde31ce10ae29936c18894
7
+ data.tar.gz: 06206e1a91e23706c6a83c02357b31064124a21e522f3144d4ec93d4d4e7863e82e38cf4b561eedb662e59ea801120ee05f8cd3fff1b414da5ea5a069dd337ff
data/CHANGELOG CHANGED
@@ -11,3 +11,14 @@ Changelog
11
11
 
12
12
  - Add InfluxDB as database.
13
13
  - WIP for daily time serie.
14
+
15
+ 1.1.1
16
+ -----
17
+
18
+ - Rescue error on no data
19
+
20
+ 1.2.0
21
+ -----
22
+
23
+ - daily subcommand now recalculates missing data
24
+ - daily subcommand also writes data to database
@@ -49,7 +49,7 @@ module StockCruncher
49
49
  config = YAML.load_file(opts['config'])
50
50
  cruncher = StockCruncher::AlphaVantage.new(config, opts['insecure'])
51
51
  raw_data = cruncher.crunch_daily(symbol, opts['full'])
52
- # TODO: export to DB here
52
+ StockCruncher::InfluxDB.new(config).export_history(symbol, raw_data)
53
53
  puts raw_data unless opts['quiet']
54
54
  end
55
55
 
@@ -13,6 +13,38 @@ 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
+
16
48
  # Method to create a new hash from two arrays of keys and values
17
49
  def create_hash(descriptions, values)
18
50
  descriptions.split(',').zip(values.split(',')).to_h
@@ -31,8 +63,15 @@ module StockCruncher
31
63
  end
32
64
 
33
65
  # Method to export historical data to database
34
- def export_history(raw)
35
- # TODO: export whole history and calculated missing values
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
36
75
  end
37
76
 
38
77
  # Method to format and array of values into comma separated string
@@ -45,6 +84,19 @@ module StockCruncher
45
84
  string
46
85
  end
47
86
 
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
+
48
100
  # Method to send http post request
49
101
  def request(url, body)
50
102
  uri = URI.parse(url)
@@ -2,5 +2,5 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module StockCruncher
5
- VERSION = '1.1.1'
5
+ VERSION = '1.2.0'
6
6
  end
@@ -5,6 +5,11 @@ require 'spec_helper'
5
5
  quote = 'symbol,open,high,low,price,volume,latestDay,previousClose,change,ch' \
6
6
  "angePercent\r\nSYM,100.0000,100.1000,99.9000,100.0000,4,2020-07-30," \
7
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"
8
13
 
9
14
  describe StockCruncher::CLI do # rubocop:disable Metrics/BlockLength
10
15
  context 'version' do
@@ -14,9 +19,15 @@ describe StockCruncher::CLI do # rubocop:disable Metrics/BlockLength
14
19
  end
15
20
  end
16
21
 
22
+ context 'daily NODATA -c spec/files/stockcruncher.yml' do
23
+ it 'Should not get any data and should fail.' do
24
+ expect { start(self) }.to raise_error(SystemExit)
25
+ end
26
+ end
27
+
17
28
  context 'daily SYM -c spec/files/stockcruncher.yml' do
18
29
  it 'Get the daily time serie for SYM.' do
19
- expect { start(self) }.to output("{}\n").to_stdout
30
+ expect { start(self) }.to output(daily).to_stdout
20
31
  end
21
32
  end
22
33
 
@@ -5,20 +5,31 @@ require 'spec_helper'
5
5
  quote = 'symbol,open,high,low,price,volume,latestDay,previousClose,change,ch' \
6
6
  "angePercent\r\nSYM,100.0000,100.1000,99.9000,100.0000,4,2020-07-30," \
7
7
  "100.0000,0.0000,0.0000%\r\n"
8
+ q_err = '{}'
9
+ daily = "timestamp,open,high,low,close,volume\r\n2020-08-03,23.8500,24.6500," \
10
+ "23.7400,24.5500,3112972\r\n2020-07-31,24.0100,24.5100,23.5900,23.81" \
11
+ "00,5482485\r\n2020-07-30,24.4700,24.6600,23.5200,23.6600,6466738\r" \
12
+ "\n2020-07-29,24.7500,25.0300,24.0400,24.5600,4605804\r\n2020-07-28," \
13
+ "25.9900,26.0700,24.5100,24.7500,6904261\r\n"
14
+ d_err = "{\n \"Error Message\": \"Invalid API call.\"\n}"
8
15
 
9
16
  RSpec.configure do |config|
10
17
  config.before(:each) do
11
18
  # requests an API without extra arguments
12
19
  stub_request(:get, 'https://www.alphavantage.co/query?' \
13
20
  'function=GLOBAL_QUOTE&symbol=NODATA&apikey=demo&datatype=csv')
14
- .to_return('status' => 200, 'body' => '{}', 'headers' => {})
21
+ .to_return('status' => 200, 'body' => q_err, 'headers' => {})
15
22
  stub_request(:get, 'https://www.alphavantage.co/query?' \
16
23
  'function=GLOBAL_QUOTE&symbol=SYM&apikey=demo&datatype=csv')
17
24
  .to_return('status' => 200, 'body' => quote, 'headers' => {})
25
+ stub_request(:get, 'https://www.alphavantage.co/query?' \
26
+ 'function=TIME_SERIES_DAILY&symbol=NODATA&apikey=demo' \
27
+ '&datatype=csv&outputsize=compact')
28
+ .to_return('status' => 200, 'body' => d_err, 'headers' => {})
18
29
  stub_request(:get, 'https://www.alphavantage.co/query?' \
19
30
  'function=TIME_SERIES_DAILY&symbol=SYM&apikey=demo' \
20
31
  '&datatype=csv&outputsize=compact')
21
- .to_return('status' => 200, 'body' => '{}', 'headers' => {})
32
+ .to_return('status' => 200, 'body' => daily, 'headers' => {})
22
33
  stub_request(:post, 'http://localhost:8086/write?db=test')
23
34
  .to_return('status' => 204, 'body' => '', 'headers' => {})
24
35
  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.1.1
4
+ version: 1.2.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-08-03 00:00:00.000000000 Z
11
+ date: 2020-08-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler