quantitative 0.1.6 → 0.1.7

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
  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