quantitative 0.1.6 → 0.1.7

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: 72d65b65fdcbb81650fcce3233f3fbde9c99c4b9b9ace1ce3bbc3b8e565152f9
4
- data.tar.gz: f687ab3c32e88ffc579a9f92ff428846f91e60ff166d3b4379963deb15a88425
3
+ metadata.gz: 8c2f8345b245cd469b234752f2fb757a1006b6a04322412acbb3fc10bd759827
4
+ data.tar.gz: fa5388e69c9f82fe686424dcfd81d8795ea6814a4b2b98b0edb6a52598ffbdaf
5
5
  SHA512:
6
- metadata.gz: 594d57a819ce8d561c064f685353d27ef4dfd1cb2e76e5cf07758bcedb1c501d2bc06859aff89cf6f4bc744e327ede1290e31b4d4ffb1daed99d614735eb0a76
7
- data.tar.gz: 5fbfb29d1501a3562788abf83ef4fcb78bcb17fcfc030e7543b42f3c29c2a7a5c3c8fba187494d4655691e117e383af59bca428764f49fd7e41fcef911ef6d40
6
+ metadata.gz: bb3c3cc8db589f5051d9dcd921fc1c01292897c440cfdb72c45df568051213ddd3fad5aa27e40652aff452619eefa835dcc4675120d050c9a46bbf34e83be3cc
7
+ data.tar.gz: cfcc8acf5989103a9a59b84965b3d1d3eb1f3288737afa3636f684ea5f378e10d82f4bda5e487f9a1ddcb867abd0fb82cef4048219acac6ee98bcfd412124db5
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- quantitative (0.1.6)
4
+ quantitative (0.1.7)
5
5
  oj (~> 3.10)
6
6
 
7
7
  GEM
@@ -4,10 +4,8 @@ module Quant
4
4
  class Indicators
5
5
  class Indicator
6
6
  include Enumerable
7
-
8
- # # include Mixins::TrendMethods
9
- # include Mixins::Trig
10
- # include Mixins::WeightedAverage
7
+ include Mixins::Functions
8
+ include Mixins::MovingAverages
11
9
  # include Mixins::HilbertTransform
12
10
  # include Mixins::SuperSmoother
13
11
  # include Mixins::Stochastic
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Quant
4
+ module Mixins
5
+ module ExponentialMovingAverage
6
+ # Computes the Exponential Moving Average (EMA) of the given period.
7
+ #
8
+ # The EMA computation is optimized to compute using just the last two
9
+ # indicator data points and is expected to be called in each indicator's
10
+ # `#compute` method for each iteration on the series.
11
+ #
12
+ # @param source [Symbol] the source of the data points to be used in the calculation.
13
+ # @param previous [Symbol] the previous EMA value.
14
+ # @param period [Integer] the number of elements to compute the EMA over.
15
+ # @return [Float] the exponential moving average of the period.
16
+ # @raise [ArgumentError] if the source is not a Symbol.
17
+ # @example
18
+ # def compute
19
+ # p0.ema = exponential_moving_average(:close_price, period: 3)
20
+ # end
21
+ #
22
+ # def compute
23
+ # p0.ema = exponential_moving_average(:close_price, previous: :ema, period: 3)
24
+ # end
25
+ def exponential_moving_average(source, period:, previous: :ema)
26
+ raise ArgumentError, "source must be a Symbol" unless source.is_a?(Symbol)
27
+ raise ArgumentError, "previous must be a Symbol" unless previous.is_a?(Symbol)
28
+
29
+ alpha = bars_to_alpha(period)
30
+ p0.send(source) * alpha + p1.send(previous) * (1.0 - alpha)
31
+ end
32
+ alias ema exponential_moving_average
33
+ end
34
+ end
35
+ end
@@ -1,66 +1,53 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "trig"
3
+ require_relative "functions"
4
4
 
5
5
  module Quant
6
6
  module Mixins
7
- # 1. All the common filters useful for traders have a transfer response that can be written
8
- # as a ratio of two polynomials.
9
- # 2. Lag is very important to traders. More complex filters can be created using more input data,
10
- # but more input data increases lag. Sophisticated filters are not very useful for trading
11
- # because they incur too much lag.
12
- # 3. Filter transfer response can be viewed in the time domain and the frequency domain with equal validity.
13
- # 4. Nonrecursive filters can have zeros in the transfer response, enabling the complete cancellation of
14
- # some selected frequency components.
15
- # 5. Nonrecursive filters having coefficients symmetrical about the center of the filter will have a delay
16
- # of half the degree of the transfer response polynomial at all frequencies.
17
- # 6. Low-pass filters are smoothers because they attenuate the high-frequency components of the input data.
18
- # 7. High-pass filters are detrenders because they attenuate the low-frequency components of trends.
19
- # 8. Band-pass filters are both detrenders and smoothers because they attenuate all but the desired frequency components.
20
- # 9. Filters provide an output only through their transfer response. The transfer response is strictly a
21
- # mathematical function, and interpretations such as overbought, oversold, convergence, divergence,
22
- # and so on are not implied. The validity of such interpretations must be made on the basis of
23
- # statistics apart from the filter.
24
- # 10. The critical period of a filter output is the frequency at which the output power of the filter
25
- # is half the power of the input wave at that frequency.
7
+ # 1. All the common filters useful for traders have a transfer response
8
+ # that can be written as a ratio of two polynomials.
9
+ # 2. Lag is very important to traders. More complex filters can be
10
+ # created using more input data, but more input data increases lag.
11
+ # Sophisticated filters are not very useful for trading because they
12
+ # incur too much lag.
13
+ # 3. Filter transfer response can be viewed in the time domain and
14
+ # the frequency domain with equal validity.
15
+ # 4. Nonrecursive filters can have zeros in the transfer response, enabling
16
+ # the complete cancellation of some selected frequency components.
17
+ # 5. Nonrecursive filters having coefficients symmetrical about the
18
+ # center of the filter will have a delay of half the degree of the
19
+ # transfer response polynomial at all frequencies.
20
+ # 6. Low-pass filters are smoothers because they attenuate the high-frequency
21
+ # components of the input data.
22
+ # 7. High-pass filters are detrenders because they attenuate the
23
+ # low-frequency components of trends.
24
+ # 8. Band-pass filters are both detrenders and smoothers because they
25
+ # attenuate all but the desired frequency components.
26
+ # 9. Filters provide an output only through their transfer response.
27
+ # The transfer response is strictly a mathematical function, and
28
+ # interpretations such as overbought, oversold, convergence, divergence,
29
+ # and so on are not implied. The validity of such interpretations
30
+ # must be made on the basis of statistics apart from the filter.
31
+ # 10. The critical period of a filter output is the frequency at which
32
+ # the output power of the filter is half the power of the input
33
+ # wave at that frequency.
26
34
  # 11. A WMA has little or no redeeming virtue.
27
- # 12. A median filter is best used when the data contain impulsive noise or when there are wild
28
- # variations in the data. Smoothing volume data is one example of a good application for a
29
- # median filter.
35
+ # 12. A median filter is best used when the data contain impulsive noise
36
+ # or when there are wild variations in the data. Smoothing volume
37
+ # data is one example of a good application for a median filter.
38
+ #
39
+ # == Filter Coefficients forVariousTypes of Filters
40
+ #
41
+ # Filter Type b0 b1 b2 a0 a1 a2
42
+ # EMA α 0 0 1 −(1−α) 0
43
+ # Two-pole low-pass α**2 0 0 1 −2*(1-α) (1-α)**2
44
+ # High-pass (1-α/2) -(1-α/2) 0 1 −(1−α) 0
45
+ # Two-pole high-pass (1-α/2)**2 -2*(1-α/2)**2 (1-α/2)**2 1 -2*(1-α) (1-α)**2
46
+ # Band-pass (1-σ)/2 0 -(1-σ)/2 1 -λ*(1+σ) σ
47
+ # Band-stop (1+σ)/2 -2λ*(1+σ)/2 (1+σ)/2 1 -λ*(1+σ) σ
30
48
  #
31
- # Filter Coefficients forVariousTypes of Filters
32
- # Filter Type b0 b1 b2 a0 a1 a2
33
- # EMA α 0 0 1 −(1−α) 0
34
- # Two-pole low-pass α**2 0 0 1 −2*(1-α) (1-α)**2
35
- # High-pass (1-α/2) -(1-α/2) 0 1 −(1−α) 0
36
- # Two-pole high-pass (1-α/2)**2 -2*(1-α/2)**2 (1-α/2)**2 1 -2*(1-α) (1-α)**2
37
- # Band-pass (1-σ)/2 0 -(1-σ)/2 1 -λ*(1+σ) σ
38
- # Band-stop (1+σ)/2 -2λ*(1+σ)/2 (1+σ)/2 1 -λ*(1+σ) σ
39
49
  module Filters
40
- include Mixins::Trig
41
-
42
- # α = Cos(K*360/Period)+Sin(K*360/Period)−1 / Cos(K*360/Period)
43
- # k = 1.0 for single-pole filters
44
- # k = 0.707 for two-pole high-pass filters
45
- # k = 1.414 for two-pole low-pass filters
46
- def period_to_alpha(period, k: 1.0)
47
- radians = deg2rad(k * 360 / period)
48
- cos = Math.cos(radians)
49
- sin = Math.sin(radians)
50
- (cos + sin - 1) / cos
51
- end
52
-
53
- # 3 bars = 0.5
54
- # 4 bars = 0.4
55
- # 5 bars = 0.333
56
- # 6 bars = 0.285
57
- # 10 bars = 0.182
58
- # 20 bars = 0.0952
59
- # 40 bars = 0.0488
60
- # 50 bars = 0.0392
61
- def bars_to_alpha(bars)
62
- 2.0 / (bars + 1)
63
- end
50
+ include Mixins::Functions
64
51
 
65
52
  def ema(source, prev_source, period)
66
53
  alpha = bars_to_alpha(period)
@@ -2,7 +2,30 @@
2
2
 
3
3
  module Quant
4
4
  module Mixins
5
- module Trig
5
+ module Functions
6
+ # α = Cos(K*360/Period)+Sin(K*360/Period)−1 / Cos(K*360/Period)
7
+ # k = 1.0 for single-pole filters
8
+ # k = 0.707 for two-pole high-pass filters
9
+ # k = 1.414 for two-pole low-pass filters
10
+ def period_to_alpha(period, k: 1.0)
11
+ radians = deg2rad(k * 360 / period)
12
+ cos = Math.cos(radians)
13
+ sin = Math.sin(radians)
14
+ (cos + sin - 1) / cos
15
+ end
16
+
17
+ # 3 bars = 0.5
18
+ # 4 bars = 0.4
19
+ # 5 bars = 0.333
20
+ # 6 bars = 0.285
21
+ # 10 bars = 0.182
22
+ # 20 bars = 0.0952
23
+ # 40 bars = 0.0488
24
+ # 50 bars = 0.0392
25
+ def bars_to_alpha(bars)
26
+ 2.0 / (bars + 1)
27
+ end
28
+
6
29
  def deg2rad(degrees)
7
30
  degrees * Math::PI / 180.0
8
31
  end
@@ -1,86 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "weighted_moving_average"
4
+ require_relative "simple_moving_average"
5
+ require_relative "exponential_moving_average"
3
6
  module Quant
4
7
  module Mixins
5
8
  module MovingAverages
6
- using Quant
7
-
8
- # Computes the Weighted Moving Average (WMA) of the series, using the four most recent data points.
9
- #
10
- # @param source [Symbol] the source of the data points to be used in the calculation.
11
- # @return [Float] the weighted average of the series.
12
- # @raise [ArgumentError] if the source is not a Symbol.
13
- # @example
14
- # p0.wma = weighted_average(:close_price)
15
- def weighted_moving_average(source)
16
- raise ArgumentError, "source must be a Symbol" unless source.is_a?(Symbol)
17
-
18
- [4.0 * p0.send(source),
19
- 3.0 * p1.send(source),
20
- 2.0 * p2.send(source),
21
- p3.send(source)].sum / 10.0
22
- end
23
- alias wma weighted_moving_average
24
-
25
- # Computes the Weighted Moving Average (WMA) of the series, using the seven most recent data points.
26
- #
27
- # @param source [Symbol] the source of the data points to be used in the calculation.
28
- # @return [Float] the weighted average of the series.
29
- # @raise [ArgumentError] if the source is not a Symbol.
30
- # @example
31
- # p0.wma = weighted_average(:close_price)
32
- def extended_weighted_moving_average(source)
33
- raise ArgumentError, "source must be a Symbol" unless source.is_a?(Symbol)
34
-
35
- [7.0 * p0.send(source),
36
- 6.0 * p1.send(source),
37
- 5.0 * p2.send(source),
38
- 4.0 * p3.send(source),
39
- 3.0 * p(4).send(source),
40
- 2.0 * p(5).send(source),
41
- p(6).send(source)].sum / 28.0
42
- end
43
- alias ewma extended_weighted_moving_average
44
-
45
- # Computes the Simple Moving Average (SMA) of the given period.
46
- #
47
- # @param source [Symbol] the source of the data points to be used in the calculation.
48
- # @param period [Integer] the number of elements to compute the SMA over.
49
- # @return [Float] the simple moving average of the period.
50
- def simple_moving_average(source, period:)
51
- raise ArgumentError, "source must be a Symbol" unless source.is_a?(Symbol)
52
-
53
- values.last(period).map { |value| value.send(source) }.mean
54
- end
55
- alias sma simple_moving_average
56
-
57
- # Computes the Exponential Moving Average (EMA) of the given period.
58
- #
59
- # The EMA computation is optimized to compute using just the last two
60
- # indicator data points and is expected to be called in each indicator's
61
- # `#compute` method for each iteration on the series.
62
- #
63
- # @param source [Symbol] the source of the data points to be used in the calculation.
64
- # @param previous [Symbol] the previous EMA value.
65
- # @param period [Integer] the number of elements to compute the EMA over.
66
- # @return [Float] the exponential moving average of the period.
67
- # @raise [ArgumentError] if the source is not a Symbol.
68
- # @example
69
- # def compute
70
- # p0.ema = exponential_moving_average(:close_price, period: 3)
71
- # end
72
- #
73
- # def compute
74
- # p0.ema = exponential_moving_average(:close_price, previous: :ema, period: 3)
75
- # end
76
- def exponential_moving_average(source, previous: :ema, period:)
77
- raise ArgumentError, "source must be a Symbol" unless source.is_a?(Symbol)
78
- raise ArgumentError, "previous must be a Symbol" unless previous.is_a?(Symbol)
79
-
80
- alpha = 2.0 / (period + 1)
81
- p0.send(source) * alpha + p1.send(previous) * (1.0 - alpha)
82
- end
83
- alias ema exponential_moving_average
9
+ include WeightedMovingAverage
10
+ include SimpleMovingAverage
11
+ include ExponentialMovingAverage
84
12
  end
85
13
  end
86
14
  end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Quant
4
+ module Mixins
5
+ module SimpleMovingAverage
6
+ using Quant
7
+
8
+ # Computes the Simple Moving Average (SMA) of the given period.
9
+ #
10
+ # @param source [Symbol] the source of the data points to be used in the calculation.
11
+ # @param period [Integer] the number of elements to compute the SMA over.
12
+ # @return [Float] the simple moving average of the period.
13
+ def simple_moving_average(source, period:)
14
+ raise ArgumentError, "source must be a Symbol" unless source.is_a?(Symbol)
15
+
16
+ values.last(period).map { |value| value.send(source) }.mean
17
+ end
18
+ alias sma simple_moving_average
19
+ end
20
+ end
21
+ end
@@ -3,73 +3,29 @@
3
3
  module Quant
4
4
  module Mixins
5
5
  module SuperSmoother
6
- def super_smoother(source, prev_source, period)
7
- v0 = (source.is_a?(Symbol) ? p0.send(source) : source).to_d
8
- return v0.to_f if points.size < 4
6
+ def two_pole_super_smooth(source, period:, previous: :ss)
7
+ raise ArgumentError, "source must be a Symbol" unless source.is_a?(Symbol)
9
8
 
10
- k = Math.exp(-Math.sqrt(2) * Math::PI / period)
11
- coef3 = -k**2
12
- coef2 = 2.0 * k * Math.cos(Math.sqrt(2) * (Math::PI / 2) / period)
13
- coef1 = 1.0 - coef2 - coef3
14
-
15
- v1 = p1.send(prev_source).to_d
16
- v2 = p2.send(prev_source).to_d
17
- p3.send(prev_source).to_d
18
- ((coef1 * (v0 + v1)) / 2.0 + (coef2 * v1) + (coef3 * v2)).to_f
19
- end
20
-
21
- def two_pole_super_smooth(source, prev_source, ssperiod)
22
- return p1.send(source) if [p1 == p3]
23
-
24
- radians = Math::PI * Math.sqrt(2) / ssperiod
9
+ radians = Math::PI * Math.sqrt(2) / period
25
10
  a1 = Math.exp(-radians)
26
11
 
27
- coef2 = 2.0 * a1 * Math.cos(radians)
12
+ coef2 = 2.0r * a1 * Math.cos(radians)
28
13
  coef3 = -a1 * a1
29
14
  coef1 = 1.0 - coef2 - coef3
30
15
 
31
- v0 = (p1.send(source) + p2.send(source)) / 2.0
32
- v1 = p2.send(prev_source)
33
- v2 = p3.send(prev_source)
34
- (coef1 * v0) + (coef2 * v1) + (coef3 * v2)
16
+ v0 = (p0.send(source) + p1.send(source))/2.0
17
+ v1 = p2.send(previous)
18
+ v2 = p3.send(previous)
19
+ ((coef1 * v0) + (coef2 * v1) + (coef3 * v2)).to_f
35
20
  end
21
+ alias super_smoother two_pole_super_smooth
22
+ alias ss2p two_pole_super_smooth
36
23
 
37
- def three_pole_super_smooth(source, prev_source, ssperiod)
38
- a1 = Math.exp(-Math::PI / ssperiod)
39
- b1 = 2 * a1 * Math.cos(Math::PI * Math.sqrt(3) / ssperiod)
40
- c1 = a1**2
24
+ def three_pole_super_smooth(source, period:, previous: :ss)
25
+ raise ArgumentError, "source must be a Symbol" unless source.is_a?(Symbol)
41
26
 
42
- coef2 = b1 + c1
43
- coef3 = -(c1 + b1 * c1)
44
- coef4 = c1**2
45
- coef1 = 1 - coef2 - coef3 - coef4
46
-
47
- p0 = prev(0)
48
- p1 = prev(1)
49
- p2 = prev(2)
50
- p3 = prev(3)
51
-
52
- v0 = source.is_a?(Symbol) ? p0.send(source) : source
53
- return v0 if [p0, p1, p2].include?(p3)
54
-
55
- v1 = p1.send(prev_source)
56
- v2 = p2.send(prev_source)
57
- v3 = p3.send(prev_source)
58
- (coef1 * v0) + (coef2 * v1) + (coef3 * v2) + (coef4 * v3)
59
- end
60
-
61
- # super smoother 3 pole
62
- def ss3p(source, prev_source, ssperiod)
63
- p0 = points[-1]
64
- p1 = points[-2] || p0
65
- p2 = points[-3] || p1
66
- p3 = points[-4] || p2
67
-
68
- v0 = source.is_a?(Symbol) ? p0.send(source) : source
69
- return v0 if p0 == p3
70
-
71
- a1 = Math.exp(-Math::PI / ssperiod)
72
- b1 = 2 * a1 * Math.cos(Math::PI * Math.sqrt(3) / ssperiod)
27
+ a1 = Math.exp(-Math::PI / period)
28
+ b1 = 2 * a1 * Math.cos(Math::PI * Math.sqrt(3) / period)
73
29
  c1 = a1**2
74
30
 
75
31
  coef2 = b1 + c1
@@ -77,56 +33,14 @@ module Quant
77
33
  coef4 = c1**2
78
34
  coef1 = 1 - coef2 - coef3 - coef4
79
35
 
80
- v1 = p1.send(prev_source)
81
- v2 = p2.send(prev_source)
82
- v3 = p3.send(prev_source)
36
+ v0 = p0.send(source)
37
+ v1 = p1.send(previous)
38
+ v2 = p2.send(previous)
39
+ v3 = p3.send(previous)
40
+
83
41
  (coef1 * v0) + (coef2 * v1) + (coef3 * v2) + (coef4 * v3)
84
42
  end
85
-
86
- # attr_reader :hpfs, :value1s, :hpf_psns
87
-
88
- # def hpf
89
- # @hpfs[-1]
90
- # end
91
-
92
- # def hpf_psn
93
- # @hpf_psns[-1]
94
- # end
95
-
96
- # def prev offset, source
97
- # idx = offset + 1
98
- # source[[-idx, -source.size].max]
99
- # end
100
-
101
- # def weighted_average source
102
- # [ 4.0 * prev(0, source),
103
- # 3.0 * prev(1, source),
104
- # 2.0 * prev(2, source),
105
- # prev(3, source),
106
- # ].sum / 10.0
107
- # end
108
-
109
- # def compute_hpf
110
- # @hpfs ||= []
111
- # @value1s ||= []
112
- # @hpf_psns ||= []
113
- # max_cycle = period * 10
114
-
115
- # r = (360.0 / max_cycle) * (Math::PI / 180)
116
- # alpha = (1 - Math::sin(r)) / Math::cos(r)
117
- # hpf = @hpfs.empty? ? 0.0 : (0.5 * (1.0 + alpha) * (current_value - prev_value(1))) + (alpha * (@hpfs[-1]))
118
-
119
- # @hpfs << hpf
120
- # @hpfs.shift if @hpfs.size > max_cycle
121
-
122
- # hh = @hpfs.max
123
- # ll = @hpfs.min
124
- # @value1s << value1 = (hh == ll ? 0.0 : 100 * (hpf - ll) / (hh - ll))
125
- # @value1s.shift if @value1s.size > max_cycle
126
-
127
- # @hpf_psns << weighted_average(@value1s)
128
- # @hpf_psns.shift if @hpf_psns.size > max_cycle
129
- # end
43
+ alias ss3p three_pole_super_smooth
130
44
  end
131
45
  end
132
46
  end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Quant
4
+ module Mixins
5
+ module WeightedMovingAverage
6
+ using Quant
7
+ # Computes the Weighted Moving Average (WMA) of the series, using the four most recent data points.
8
+ #
9
+ # @param source [Symbol] the source of the data points to be used in the calculation.
10
+ # @return [Float] the weighted average of the series.
11
+ # @raise [ArgumentError] if the source is not a Symbol.
12
+ # @example
13
+ # p0.wma = weighted_average(:close_price)
14
+ def weighted_moving_average(source)
15
+ raise ArgumentError, "source must be a Symbol" unless source.is_a?(Symbol)
16
+
17
+ [4.0 * p0.send(source),
18
+ 3.0 * p1.send(source),
19
+ 2.0 * p2.send(source),
20
+ p3.send(source)].sum / 10.0
21
+ end
22
+ alias wma weighted_moving_average
23
+
24
+ # Computes the Weighted Moving Average (WMA) of the series, using the seven most recent data points.
25
+ #
26
+ # @param source [Symbol] the source of the data points to be used in the calculation.
27
+ # @return [Float] the weighted average of the series.
28
+ # @raise [ArgumentError] if the source is not a Symbol.
29
+ # @example
30
+ # p0.wma = weighted_average(:close_price)
31
+ def extended_weighted_moving_average(source)
32
+ raise ArgumentError, "source must be a Symbol" unless source.is_a?(Symbol)
33
+
34
+ [7.0 * p0.send(source),
35
+ 6.0 * p1.send(source),
36
+ 5.0 * p2.send(source),
37
+ 4.0 * p3.send(source),
38
+ 3.0 * p(4).send(source),
39
+ 2.0 * p(5).send(source),
40
+ p(6).send(source)].sum / 28.0
41
+ end
42
+ alias ewma extended_weighted_moving_average
43
+ end
44
+ end
45
+ end
@@ -4,11 +4,15 @@ require_relative "tick"
4
4
 
5
5
  module Quant
6
6
  module Ticks
7
- # An {Quant::Ticks::OHLC} is a bar or candle for a point in time that has an open, high, low, and close price.
8
- # It is the most common form of a {Quant::Ticks::Tick} and is usually used to representa time period such as a
9
- # minute, hour, day, week, or month. The {Quant::Ticks::OHLC} is used to represent the price action of an asset
10
- # The interval of the {Quant::Ticks::OHLC} is the time period that the {Quant::Ticks::OHLC} represents,
11
- # such has hourly, daily, weekly, etc.
7
+ # A {Quant::Ticks::OHLC} is a bar or candle for a point in time that
8
+ # has an open, high, low, and close price. It is the most common form
9
+ # of a {Quant::Ticks::Tick} and is usually used to representa time
10
+ # period such as a minute, hour, day, week, or month.
11
+ #
12
+ # The {Quant::Ticks::OHLC} is used to represent the price action of
13
+ # an asset The interval of the {Quant::Ticks::OHLC} is the time period
14
+ # that the {Quant::Ticks::OHLC} represents, such has hourly, daily,
15
+ # weekly, etc.
12
16
  class OHLC < Tick
13
17
  include TimeMethods
14
18
 
@@ -2,22 +2,29 @@
2
2
 
3
3
  module Quant
4
4
  module Ticks
5
- # {Quant::Ticks::Tick} is the abstract ancestor for all Ticks and holds the logic for interacting with series and indicators.
6
- # The public interface is devoid of properties around price, volume, and timestamp, etc. Descendant classes
7
- # are responsible for defining the properties and how they are represented.
8
- #
9
- # The {Quant::Ticks::Tick} class is designed to be immutable and is intended to be used as a value object. This means that
10
- # once a {Quant::Ticks::Tick} is created, it cannot be changed. This is important for the integrity of the series and
11
- # indicators that depend on the ticks within the series.
12
- #
13
- # When a tick is added to a series, it is locked into the series and ownership cannot be changed. This is important
14
- # for the integrity of the series and indicators that depend on the ticks within the series. This is a key design
15
- # to being able to being able to not only compute indicators on the ticks just once, but also avoid recomputing
16
- # indicators when series are limited/sliced/filtered into subsets of the original series.
17
- #
5
+ # {Quant::Ticks::Tick} is the abstract ancestor for all Ticks and holds
6
+ # the logic for interacting with series and indicators. The public
7
+ # interface is devoid of properties around price, volume, and timestamp, etc.
8
+ # Descendant classes are responsible for defining the properties and
9
+ # how they are represented.
10
+
11
+ # The {Quant::Ticks::Tick} class is designed to be immutable and is
12
+ # intended to be used as a value object. This means that once a
13
+ # {Quant::Ticks::Tick} is created, it cannot be changed. This is important
14
+ # for the integrity of the series and indicators that depend on the
15
+ # ticks within the series.
16
+
17
+ # When a tick is added to a series, it is locked into the series and
18
+ # ownership cannot be changed. This is important for the integrity
19
+ # of the series and indicators that depend on the ticks within the series.
20
+ # This is a key design to being able to being able to not only compute
21
+ # indicators on the ticks just once, but also avoid recomputing indicators
22
+ # when series are limited/sliced/filtered into subsets of the original series.
23
+
18
24
  # Ticks can be serialized to and from Ruby Hash, JSON strings, and CSV strings.
19
25
  class Tick
20
- # Returns a {Quant::Ticks::Tick} from a Ruby +Hash+. The default serializer is used to generate the {Quant::Ticks::Tick}.
26
+ # Returns a {Quant::Ticks::Tick} from a Ruby +Hash+. The default
27
+ # serializer is used to generate the {Quant::Ticks::Tick}.
21
28
  # @param hash [Hash]
22
29
  # @param serializer_class [Class] The serializer class to use for the conversion.
23
30
  # @return [Quant::Ticks::Tick]
@@ -30,7 +37,8 @@ module Quant
30
37
  serializer_class.from(hash, tick_class: self)
31
38
  end
32
39
 
33
- # Returns a {Quant::Ticks::Tick} from a JSON string. The default serializer is used to generate the {Quant::Ticks::Tick}.
40
+ # Returns a {Quant::Ticks::Tick} from a JSON string. The default
41
+ # serializer is used to generate the {Quant::Ticks::Tick}.
34
42
  # @param json [String]
35
43
  # @param serializer_class [Class] The serializer class to use for the conversion.
36
44
  # @return [Quant::Ticks::Tick]
@@ -80,7 +88,8 @@ module Quant
80
88
  self
81
89
  end
82
90
 
83
- # Returns a Ruby hash for the Tick. The default serializer is used to generate the hash.
91
+ # Returns a Ruby hash for the Tick. The default serializer is used
92
+ # to generate the hash.
84
93
  #
85
94
  # @param serializer_class [Class] the serializer class to use for the conversion.
86
95
  # @example
@@ -90,7 +99,8 @@ module Quant
90
99
  serializer_class.to_h(self)
91
100
  end
92
101
 
93
- # Returns a JSON string for the Tick. The default serializer is used to generate the JSON string.
102
+ # Returns a JSON string for the Tick. The default serializer is used
103
+ # to generate the JSON string.
94
104
  #
95
105
  # @param serializer_class [Class] the serializer class to use for the conversion.
96
106
  # @example
@@ -100,8 +110,9 @@ module Quant
100
110
  serializer_class.to_json(self)
101
111
  end
102
112
 
103
- # Returns a CSV row as a String for the Tick. The default serializer is used to generate the CSV string.
104
- # If headers is true, two lines returned separated by newline.
113
+ # Returns a CSV row as a String for the Tick. The default serializer
114
+ # is used to generate the CSV string. If headers is true, two lines
115
+ # returned separated by newline.
105
116
  # The first line is the header row and the second line is the data row.
106
117
  #
107
118
  # @param serializer_class [Class] the serializer class to use for the conversion.
data/lib/quant/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Quant
4
- VERSION = "0.1.6"
4
+ VERSION = "0.1.7"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: quantitative
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
4
+ version: 0.1.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Lang
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-02-25 00:00:00.000000000 Z
11
+ date: 2024-02-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: oj
@@ -58,14 +58,17 @@ files:
58
58
  - lib/quant/indicators_sources.rb
59
59
  - lib/quant/interval.rb
60
60
  - lib/quant/mixins/direction.rb
61
+ - lib/quant/mixins/exponential_moving_average.rb
61
62
  - lib/quant/mixins/filters.rb
62
63
  - lib/quant/mixins/fisher_transform.rb
64
+ - lib/quant/mixins/functions.rb
63
65
  - lib/quant/mixins/high_pass_filter.rb
64
66
  - lib/quant/mixins/hilbert_transform.rb
65
67
  - lib/quant/mixins/moving_averages.rb
68
+ - lib/quant/mixins/simple_moving_average.rb
66
69
  - lib/quant/mixins/stochastic.rb
67
70
  - lib/quant/mixins/super_smoother.rb
68
- - lib/quant/mixins/trig.rb
71
+ - lib/quant/mixins/weighted_moving_average.rb
69
72
  - lib/quant/refinements/array.rb
70
73
  - lib/quant/series.rb
71
74
  - lib/quant/settings.rb