technical-analysis 0.1.1 → 0.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
  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: []