stockcruncher 1.1.1 → 1.2.0

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: 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