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 +4 -4
 - data/CHANGELOG +11 -0
 - data/lib/stockcruncher/cli.rb +1 -1
 - data/lib/stockcruncher/influxdb.rb +54 -2
 - data/lib/stockcruncher/version.rb +1 -1
 - data/spec/stockcruncher/cli_spec.rb +12 -1
 - data/spec/stockcruncher/stubs/servers_stubs.rb +13 -2
 - metadata +2 -2
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA256:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: 7bd12e5a6e5db6f83f239c1b6da9aca85931048dd427778ffb96f043e7334596
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: 48fe8efa593f30fe39c294725d7090c89a4a14413eaa59a1d6741c817fc02d64
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 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
         
     | 
    
        data/lib/stockcruncher/cli.rb
    CHANGED
    
    | 
         @@ -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 
     | 
    
         
            -
                   
     | 
| 
      
 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 
     | 
    
         
            -
                   
     | 
| 
      
 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)
         
     | 
| 
         @@ -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( 
     | 
| 
      
 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' =>  
     | 
| 
      
 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' =>  
     | 
| 
      
 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. 
     | 
| 
      
 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- 
     | 
| 
      
 11 
     | 
    
         
            +
            date: 2020-08-04 00:00:00.000000000 Z
         
     | 
| 
       12 
12 
     | 
    
         
             
            dependencies:
         
     | 
| 
       13 
13 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       14 
14 
     | 
    
         
             
              name: bundler
         
     |