technical-analysis 0.1.1 → 0.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
  SHA1:
3
- metadata.gz: c291a4476c68ca1fd7baf9279188f2caf5daf20d
4
- data.tar.gz: cf2450f8149d4f4b51581332aceb544bc69b85c1
3
+ metadata.gz: 97d8d8c26202d454f1f8b2f9da59c312a8befe4d
4
+ data.tar.gz: e64933ee1a04d1180ec5c9e45c32b2b5378da507
5
5
  SHA512:
6
- metadata.gz: f334282776b1b2cc80dd4cb3e0505179b88cfdf99a39df9a995f76198fb33c4ddcf94b94df774e413d4f9fbd0cce52168b83b43e1525aceb76c321f7ab1ddcd4
7
- data.tar.gz: 5d4d2e50b2565290af10635b7306a84544819b28e27fe1a9928ab700b6f1b365d87634134e982d8d7ab9f739d4eb3f91847f77f25a41221cfcdc6ec37f638c59
6
+ metadata.gz: d9391b85785a8594b3c3cca136c3d96868efc7754557b504b045153a24f360586823fea2eed93f5039b79e2a942b61f7ab2c398637975032b89724ed523e41fa
7
+ data.tar.gz: 1b7d990e4515a1d48186febb1dad7c29b933d2c6589a2b9192e7bd17c1078b6453e4feff679984c47d0d7af15ab1ce7149eef0a626db6e61f6c13ff899114f33
@@ -49,6 +49,7 @@ module TechnicalAnalysis
49
49
  TechnicalAnalysis::Uo,
50
50
  TechnicalAnalysis::Vi,
51
51
  TechnicalAnalysis::Vpt,
52
+ TechnicalAnalysis::Vwap,
52
53
  TechnicalAnalysis::Wr,
53
54
  ]
54
55
  end
@@ -0,0 +1,97 @@
1
+ module TechnicalAnalysis
2
+ # Volume Weighted Average Price
3
+ class Vwap < Indicator
4
+
5
+ # Returns the symbol of the technical indicator
6
+ #
7
+ # @return [String] A string of the symbol of the technical indicator
8
+ def self.indicator_symbol
9
+ "vwap"
10
+ end
11
+
12
+ # Returns the name of the technical indicator
13
+ #
14
+ # @return [String] A string of the name of the technical indicator
15
+ def self.indicator_name
16
+ "Volume Weighted Average Price"
17
+ end
18
+
19
+ # Returns an array of valid keys for options for this technical indicator
20
+ #
21
+ # @return [Array] An array of keys as symbols for valid options for this technical indicator
22
+ def self.valid_options
23
+ []
24
+ end
25
+
26
+ # Validates the provided options for this technical indicator
27
+ #
28
+ # @param options [Hash] The options for the technical indicator to be validated
29
+ #
30
+ # @return [Boolean] Returns true if options are valid or raises a ValidationError if they're not
31
+ def self.validate_options(options)
32
+ return true if options == {}
33
+ raise Validation::ValidationError.new "This indicator doesn't accept any options."
34
+ end
35
+
36
+ # Calculates the minimum number of observations needed to calculate the technical indicator
37
+ #
38
+ # @param options [Hash] The options for the technical indicator
39
+ #
40
+ # @return [Integer] Returns the minimum number of observations needed to calculate the technical
41
+ # indicator based on the options provided
42
+ def self.min_data_size(**params)
43
+ 1
44
+ end
45
+
46
+ # Calculates the volume weighted average price (VWAP) for the data
47
+ # https://en.wikipedia.org/wiki/Volume-weighted_average_price
48
+ #
49
+ # @param data [Array] Array of hashes with keys (:date_time, :high, :low, :close, :volume)
50
+ #
51
+ # @return [Array<VwapValue>] An array of VwapValue instances
52
+ def self.calculate(data)
53
+ Validation.validate_numeric_data(data, :high, :low, :close, :volume)
54
+ Validation.validate_length(data, min_data_size)
55
+ Validation.validate_date_time_key(data)
56
+
57
+ data = data.sort_by { |row| row[:date_time] }
58
+
59
+ output = []
60
+ cumm_volume = 0
61
+ cumm_volume_x_typical_price = 0
62
+
63
+ data.each do |v|
64
+ typical_price = StockCalculation.typical_price(v)
65
+ cumm_volume_x_typical_price += v[:volume] * typical_price
66
+ cumm_volume += v[:volume]
67
+ vwap = cumm_volume_x_typical_price.to_f / cumm_volume.to_f
68
+
69
+ output << VwapValue.new(date_time: v[:date_time], vwap: vwap)
70
+ end
71
+
72
+ output.sort_by(&:date_time).reverse
73
+ end
74
+
75
+ end
76
+
77
+ # The value class to be returned by calculations
78
+ class VwapValue
79
+
80
+ # @return [String] the date_time of the obversation as it was provided
81
+ attr_accessor :date_time
82
+
83
+ # @return [Float] the vwap calculation value
84
+ attr_accessor :vwap
85
+
86
+ def initialize(date_time: nil, vwap: nil)
87
+ @date_time = date_time
88
+ @vwap = vwap
89
+ end
90
+
91
+ # @return [Hash] the attributes as a hash
92
+ def to_hash
93
+ { date_time: @date_time, vwap: @vwap }
94
+ end
95
+
96
+ end
97
+ end
@@ -38,4 +38,5 @@ require 'technical_analysis/indicators/tsi'
38
38
  require 'technical_analysis/indicators/uo'
39
39
  require 'technical_analysis/indicators/vi'
40
40
  require 'technical_analysis/indicators/vpt'
41
+ require 'technical_analysis/indicators/vwap'
41
42
  require 'technical_analysis/indicators/wr'
@@ -0,0 +1,119 @@
1
+ require 'technical-analysis'
2
+ require 'spec_helper'
3
+
4
+ describe 'Indicators' do
5
+ describe "VWAP" do
6
+ input_data = SpecHelper.get_test_data(:volume, :high, :low, :close)
7
+ indicator = TechnicalAnalysis::Vwap
8
+
9
+ describe 'Volume Weighted Average Price' do
10
+ it 'Calculates VWAP' do
11
+ output = indicator.calculate(input_data)
12
+ normalized_output = output.map(&:to_hash)
13
+
14
+ expected_output = [
15
+ {:date_time=>"2019-01-09T00:00:00.000Z", :vwap=>183.55426863053765},
16
+ {:date_time=>"2019-01-08T00:00:00.000Z", :vwap=>184.06635227887782},
17
+ {:date_time=>"2019-01-07T00:00:00.000Z", :vwap=>184.57507590747517},
18
+ {:date_time=>"2019-01-04T00:00:00.000Z", :vwap=>185.3413093796368},
19
+ {:date_time=>"2019-01-03T00:00:00.000Z", :vwap=>186.19781421865375},
20
+ {:date_time=>"2019-01-02T00:00:00.000Z", :vwap=>187.76843731172002},
21
+ {:date_time=>"2018-12-31T00:00:00.000Z", :vwap=>188.21552447966795},
22
+ {:date_time=>"2018-12-28T00:00:00.000Z", :vwap=>188.64862275471472},
23
+ {:date_time=>"2018-12-27T00:00:00.000Z", :vwap=>189.2144975598256},
24
+ {:date_time=>"2018-12-26T00:00:00.000Z", :vwap=>189.9889456493791},
25
+ {:date_time=>"2018-12-24T00:00:00.000Z", :vwap=>190.91953458787302},
26
+ {:date_time=>"2018-12-21T00:00:00.000Z", :vwap=>191.6297166885398},
27
+ {:date_time=>"2018-12-20T00:00:00.000Z", :vwap=>193.36567531270202},
28
+ {:date_time=>"2018-12-19T00:00:00.000Z", :vwap=>194.463693818502},
29
+ {:date_time=>"2018-12-18T00:00:00.000Z", :vwap=>195.21670632642397},
30
+ {:date_time=>"2018-12-17T00:00:00.000Z", :vwap=>195.7127882800064},
31
+ {:date_time=>"2018-12-14T00:00:00.000Z", :vwap=>196.3956319251192},
32
+ {:date_time=>"2018-12-13T00:00:00.000Z", :vwap=>197.03092567150182},
33
+ {:date_time=>"2018-12-12T00:00:00.000Z", :vwap=>197.47196479514173},
34
+ {:date_time=>"2018-12-11T00:00:00.000Z", :vwap=>198.00221355940155},
35
+ {:date_time=>"2018-12-10T00:00:00.000Z", :vwap=>198.7429667210245},
36
+ {:date_time=>"2018-12-07T00:00:00.000Z", :vwap=>199.85255982037654},
37
+ {:date_time=>"2018-12-06T00:00:00.000Z", :vwap=>200.57927838438474},
38
+ {:date_time=>"2018-12-04T00:00:00.000Z", :vwap=>201.28731920049952},
39
+ {:date_time=>"2018-12-03T00:00:00.000Z", :vwap=>201.8731568533139},
40
+ {:date_time=>"2018-11-30T00:00:00.000Z", :vwap=>202.34554208942396},
41
+ {:date_time=>"2018-11-29T00:00:00.000Z", :vwap=>202.95867828112358},
42
+ {:date_time=>"2018-11-28T00:00:00.000Z", :vwap=>203.60135199869035},
43
+ {:date_time=>"2018-11-27T00:00:00.000Z", :vwap=>204.38651817163168},
44
+ {:date_time=>"2018-11-26T00:00:00.000Z", :vwap=>205.30361785858756},
45
+ {:date_time=>"2018-11-23T00:00:00.000Z", :vwap=>206.36274937523916},
46
+ {:date_time=>"2018-11-21T00:00:00.000Z", :vwap=>206.94494917055295},
47
+ {:date_time=>"2018-11-20T00:00:00.000Z", :vwap=>207.6427516507437},
48
+ {:date_time=>"2018-11-19T00:00:00.000Z", :vwap=>209.27699957144853},
49
+ {:date_time=>"2018-11-16T00:00:00.000Z", :vwap=>210.05211892678065},
50
+ {:date_time=>"2018-11-15T00:00:00.000Z", :vwap=>210.59952347188045},
51
+ {:date_time=>"2018-11-14T00:00:00.000Z", :vwap=>211.4589551886514},
52
+ {:date_time=>"2018-11-13T00:00:00.000Z", :vwap=>212.75803369499064},
53
+ {:date_time=>"2018-11-12T00:00:00.000Z", :vwap=>213.6551619737374},
54
+ {:date_time=>"2018-11-09T00:00:00.000Z", :vwap=>214.61043573066618},
55
+ {:date_time=>"2018-11-08T00:00:00.000Z", :vwap=>215.00076838969952},
56
+ {:date_time=>"2018-11-07T00:00:00.000Z", :vwap=>215.18761540540189},
57
+ {:date_time=>"2018-11-06T00:00:00.000Z", :vwap=>215.4663555747261},
58
+ {:date_time=>"2018-11-05T00:00:00.000Z", :vwap=>215.93354729003553},
59
+ {:date_time=>"2018-11-02T00:00:00.000Z", :vwap=>217.20680955786048},
60
+ {:date_time=>"2018-11-01T00:00:00.000Z", :vwap=>218.35223508156088},
61
+ {:date_time=>"2018-10-31T00:00:00.000Z", :vwap=>218.1692825392702},
62
+ {:date_time=>"2018-10-30T00:00:00.000Z", :vwap=>218.13783195840017},
63
+ {:date_time=>"2018-10-29T00:00:00.000Z", :vwap=>218.5155747290589},
64
+ {:date_time=>"2018-10-26T00:00:00.000Z", :vwap=>219.05970452474796},
65
+ {:date_time=>"2018-10-25T00:00:00.000Z", :vwap=>219.3440526461074},
66
+ {:date_time=>"2018-10-24T00:00:00.000Z", :vwap=>219.34643675779574},
67
+ {:date_time=>"2018-10-23T00:00:00.000Z", :vwap=>219.4951598586493},
68
+ {:date_time=>"2018-10-22T00:00:00.000Z", :vwap=>219.41092910048724},
69
+ {:date_time=>"2018-10-19T00:00:00.000Z", :vwap=>219.26375336145847},
70
+ {:date_time=>"2018-10-18T00:00:00.000Z", :vwap=>219.25541442468506},
71
+ {:date_time=>"2018-10-17T00:00:00.000Z", :vwap=>219.65735634491844},
72
+ {:date_time=>"2018-10-16T00:00:00.000Z", :vwap=>219.5125052055069},
73
+ {:date_time=>"2018-10-15T00:00:00.000Z", :vwap=>219.34283327445593},
74
+ {:date_time=>"2018-10-12T00:00:00.000Z", :vwap=>219.44169580294155},
75
+ {:date_time=>"2018-10-11T00:00:00.000Z", :vwap=>219.0592293697168},
76
+ {:date_time=>"2018-10-10T00:00:00.000Z", :vwap=>221.89869420553177},
77
+ {:date_time=>"2018-10-09T00:00:00.000Z", :vwap=>225.4620666666667}
78
+ ]
79
+
80
+ expect(normalized_output).to eq(expected_output)
81
+ end
82
+
83
+ it "Throws exception if not enough data" do
84
+ expect {indicator.calculate([])}.to raise_exception(TechnicalAnalysis::Validation::ValidationError)
85
+ end
86
+
87
+ it 'Returns the symbol' do
88
+ indicator_symbol = indicator.indicator_symbol
89
+ expect(indicator_symbol).to eq('vwap')
90
+ end
91
+
92
+ it 'Returns the name' do
93
+ indicator_name = indicator.indicator_name
94
+ expect(indicator_name).to eq('Volume Weighted Average Price')
95
+ end
96
+
97
+ it 'Returns the valid options' do
98
+ valid_options = indicator.valid_options
99
+ expect(valid_options).to eq([])
100
+ end
101
+
102
+ it 'Validates options' do
103
+ valid_options = {}
104
+ options_validated = indicator.validate_options(valid_options)
105
+ expect(options_validated).to eq(true)
106
+ end
107
+
108
+ it 'Throws exception for invalid options' do
109
+ invalid_options = { test: 10 }
110
+ expect { indicator.validate_options(invalid_options) }.to raise_exception(TechnicalAnalysis::Validation::ValidationError)
111
+ end
112
+
113
+ it 'Calculates minimum data size' do
114
+ options = {}
115
+ expect(indicator.min_data_size(options)).to eq(1)
116
+ end
117
+ end
118
+ end
119
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: technical-analysis
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Intrinio
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-03-06 00:00:00.000000000 Z
11
+ date: 2019-03-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -112,6 +112,7 @@ files:
112
112
  - lib/technical_analysis/indicators/uo.rb
113
113
  - lib/technical_analysis/indicators/vi.rb
114
114
  - lib/technical_analysis/indicators/vpt.rb
115
+ - lib/technical_analysis/indicators/vwap.rb
115
116
  - lib/technical_analysis/indicators/wr.rb
116
117
  - spec/helpers/array_helper_spec.rb
117
118
  - spec/helpers/validaton_spec.rb
@@ -150,6 +151,7 @@ files:
150
151
  - spec/technical_analysis/indicators/uo_spec.rb
151
152
  - spec/technical_analysis/indicators/vi_spec.rb
152
153
  - spec/technical_analysis/indicators/vpt_spec.rb
154
+ - spec/technical_analysis/indicators/vwap_spec.rb
153
155
  - spec/technical_analysis/indicators/wr_spec.rb
154
156
  homepage: https://github.com/intrinio/technical-analysis
155
157
  licenses: []