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:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 97d8d8c26202d454f1f8b2f9da59c312a8befe4d
|
4
|
+
data.tar.gz: e64933ee1a04d1180ec5c9e45c32b2b5378da507
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d9391b85785a8594b3c3cca136c3d96868efc7754557b504b045153a24f360586823fea2eed93f5039b79e2a942b61f7ab2c398637975032b89724ed523e41fa
|
7
|
+
data.tar.gz: 1b7d990e4515a1d48186febb1dad7c29b933d2c6589a2b9192e7bd17c1078b6453e4feff679984c47d0d7af15ab1ce7149eef0a626db6e61f6c13ff899114f33
|
@@ -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
|
data/lib/technical_analysis.rb
CHANGED
@@ -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.
|
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-
|
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: []
|