quantitative 0.2.1 → 0.3.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.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +9 -4
  3. data/Gemfile.lock +9 -1
  4. data/README.md +5 -0
  5. data/lib/quant/{indicators/dominant_cycle_indicators.rb → dominant_cycles_source.rb} +19 -8
  6. data/lib/quant/experimental.rb +8 -1
  7. data/lib/quant/indicators/adx.rb +83 -0
  8. data/lib/quant/indicators/atr.rb +79 -0
  9. data/lib/quant/indicators/cci.rb +63 -0
  10. data/lib/quant/indicators/decycler.rb +71 -0
  11. data/lib/quant/indicators/dominant_cycles/acr.rb +2 -0
  12. data/lib/quant/indicators/dominant_cycles/band_pass.rb +2 -0
  13. data/lib/quant/indicators/dominant_cycles/differential.rb +3 -1
  14. data/lib/quant/indicators/dominant_cycles/dominant_cycle.rb +12 -6
  15. data/lib/quant/indicators/dominant_cycles/half_period.rb +2 -0
  16. data/lib/quant/indicators/dominant_cycles/homodyne.rb +4 -2
  17. data/lib/quant/indicators/dominant_cycles/phase_accumulator.rb +8 -4
  18. data/lib/quant/indicators/frama.rb +50 -0
  19. data/lib/quant/indicators/indicator.rb +50 -2
  20. data/lib/quant/indicators/mama.rb +143 -0
  21. data/lib/quant/indicators/mesa.rb +86 -0
  22. data/lib/quant/indicators/pivot.rb +107 -0
  23. data/lib/quant/indicators/pivots/atr.rb +41 -0
  24. data/lib/quant/indicators/pivots/bollinger.rb +45 -0
  25. data/lib/quant/indicators/pivots/camarilla.rb +61 -0
  26. data/lib/quant/indicators/pivots/classic.rb +24 -0
  27. data/lib/quant/indicators/pivots/demark.rb +50 -0
  28. data/lib/quant/indicators/pivots/donchian.rb +40 -0
  29. data/lib/quant/indicators/pivots/fibbonacci.rb +22 -0
  30. data/lib/quant/indicators/pivots/guppy.rb +39 -0
  31. data/lib/quant/indicators/pivots/keltner.rb +43 -0
  32. data/lib/quant/indicators/pivots/murrey.rb +34 -0
  33. data/lib/quant/indicators/pivots/traditional.rb +36 -0
  34. data/lib/quant/indicators/pivots/woodie.rb +59 -0
  35. data/lib/quant/indicators_source.rb +140 -0
  36. data/lib/quant/indicators_sources.rb +36 -10
  37. data/lib/quant/mixins/stochastic.rb +1 -1
  38. data/lib/quant/mixins/super_smoother.rb +11 -2
  39. data/lib/quant/pivots_source.rb +28 -0
  40. data/lib/quant/refinements/array.rb +14 -0
  41. data/lib/quant/series.rb +8 -19
  42. data/lib/quant/settings/indicators.rb +11 -0
  43. data/lib/quant/version.rb +1 -1
  44. data/possibilities.png +0 -0
  45. data/quantitative.gemspec +39 -0
  46. metadata +27 -5
  47. data/lib/quant/indicators.rb +0 -14
  48. data/lib/quant/indicators_proxy.rb +0 -68
@@ -2,6 +2,8 @@
2
2
 
3
3
  module Quant
4
4
  class Indicators
5
+ # The {Quant::Indicators::Indicator} class is the abstract ancestor for all Indicators.
6
+ #
5
7
  class Indicator
6
8
  include Enumerable
7
9
  include Mixins::Functions
@@ -13,16 +15,57 @@ module Quant
13
15
  include Mixins::FisherTransform
14
16
  # include Mixins::Direction
15
17
 
18
+ # Provides a registry of dependent indicators for each indicator class.
19
+ # NOTE: Internal use only.
20
+ def self.dependent_indicator_classes
21
+ @dependent_indicator_classes ||= Set.new
22
+ end
23
+
24
+ # Use the {depends_on} method to declare dependencies for an indicator.
25
+ # @param indicator_classes [Array<Class>] The classes of the indicators to depend on.
26
+ # @example
27
+ # class BarIndicator < Indicator
28
+ # depends_on FooIndicator
29
+ # end
30
+ def self.depends_on(*indicator_classes)
31
+ Array(indicator_classes).each{ |dependency| dependent_indicator_classes << dependency }
32
+ end
33
+
16
34
  attr_reader :source, :series
17
35
 
18
36
  def initialize(series:, source:)
19
37
  @series = series
20
38
  @source = source
21
39
  @points = {}
22
- series.new_indicator(self)
23
40
  series.each { |tick| self << tick }
24
41
  end
25
42
 
43
+ def dominant_cycle_indicator_class
44
+ Quant.config.indicators.dominant_cycle_indicator_class
45
+ end
46
+
47
+ # The priority drives the order of computations when iterating over each tick
48
+ # in a series. Generally speaking, indicators that feed values to another indicator
49
+ # must have a lower priority value than the indicator that consumes the values.
50
+ # * Most indicators will have a default priority of 1000.
51
+ # * Dominant Cycle indicators will have a priority of 100.
52
+ # * Some indicators will have a "high priority" of 500.
53
+ # Priority values are arbitrary and purposefully gapping so that new indicators
54
+ # introduced outside the core library can be slotted in between.
55
+ #
56
+ # NOTE: Priority is well-managed by the library and should not require overriding
57
+ # for a custom indicator developed outside the library. If you find yourself
58
+ # needing to override this method, please open an issue on the library's GitHub page.
59
+ PRIORITIES = [
60
+ DOMINANT_CYCLES_PRIORITY = 100,
61
+ DEPENDENCY_PRIORITY = 500,
62
+ DEFAULT_PRIORITY = 1000
63
+ ].freeze
64
+
65
+ def priority
66
+ DEFAULT_PRIORITY
67
+ end
68
+
26
69
  def min_period
27
70
  Quant.config.indicators.min_period
28
71
  end
@@ -48,7 +91,7 @@ module Quant
48
91
  end
49
92
 
50
93
  def dominant_cycle
51
- series.indicators[source].dominant_cycle
94
+ series.indicators[source][dominant_cycle_indicator_class]
52
95
  end
53
96
 
54
97
  def dc_period
@@ -71,6 +114,11 @@ module Quant
71
114
  @points.size
72
115
  end
73
116
 
117
+ def period_points(max_period)
118
+ extent = [values.size, max_period].min
119
+ values[-extent, extent]
120
+ end
121
+
74
122
  attr_reader :p0, :p1, :p2, :p3
75
123
  attr_reader :t0, :t1, :t2, :t3
76
124
 
@@ -0,0 +1,143 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Quant
4
+ class Indicators
5
+ class MamaPoint < IndicatorPoint
6
+ attribute :smooth, default: 0.0
7
+ attribute :detrend, default: 0.0
8
+ attribute :re, default: 0.0
9
+ attribute :im, default: 0.0
10
+ attribute :i1, default: 0.0
11
+ attribute :q1, default: 0.0
12
+ attribute :ji, default: 0.0
13
+ attribute :jq, default: 0.0
14
+ attribute :i2, default: 0.0
15
+ attribute :q2, default: 0.0
16
+ attribute :period, default: :min_period
17
+ attribute :smooth_period, default: :min_period
18
+ attribute :mama, default: :input
19
+ attribute :fama, default: :input
20
+ attribute :gama, default: :input
21
+ attribute :dama, default: :input
22
+ attribute :lama, default: :input
23
+ attribute :faga, default: :input
24
+ attribute :phase, default: 0.0
25
+ attribute :delta_phase, default: 0.0
26
+ attribute :osc, default: 0.0
27
+ attribute :crossed, default: :unchanged
28
+
29
+ def crossed_up?
30
+ @crossed == :up
31
+ end
32
+
33
+ def crossed_down?
34
+ @crossed == :down
35
+ end
36
+ end
37
+
38
+ # https://www.mesasoftware.com/papers/MAMA.pdf
39
+ # MESA Adaptive Moving Average (MAMA) adapts to price movement in an
40
+ # entirely new and unique way. The adapation is based on the rate change
41
+ # of phase as measured by the Hilbert Transform Discriminator.
42
+ #
43
+ # This version of Ehler's MAMA indicator duplicates the computations
44
+ # present in the homodyne version of the dominant cycle indicator.
45
+ # Use this version of the indicator when you're using a different
46
+ # dominant cycle indicator other than the homodyne for the rest
47
+ # of your indicators.
48
+ class Mama < Indicator
49
+ # constrain between 6 and 50 bars
50
+ def constrain_period_bars
51
+ p0.period = p0.period.clamp(min_period, max_period)
52
+ end
53
+
54
+ # constrain magnitude of change in phase
55
+ def constrain_period_magnitude_change
56
+ p0.period = [1.5 * p1.period, p0.period].min
57
+ p0.period = [0.67 * p1.period, p0.period].max
58
+ end
59
+
60
+ # amplitude correction using previous period value
61
+ def compute_smooth_period
62
+ p0.period = ((0.2 * p0.period) + (0.8 * p1.period)).round
63
+ p0.smooth_period = ((0.33333 * p0.period) + (0.666667 * p1.smooth_period)).round
64
+ end
65
+
66
+ def homodyne_discriminator
67
+ p0.re = (p0.i2 * p1.i2) + (p0.q2 * p1.q2)
68
+ p0.im = (p0.i2 * p1.q2) - (p0.q2 * p1.i2)
69
+
70
+ p0.re = (0.2 * p0.re) + (0.8 * p1.re)
71
+ p0.im = (0.2 * p0.im) + (0.8 * p1.im)
72
+
73
+ p0.period = 360.0 / rad2deg(Math.atan(p0.im / p0.re)) if (p0.im != 0) && (p0.re != 0)
74
+
75
+ constrain_period_magnitude_change
76
+ constrain_period_bars
77
+ compute_smooth_period
78
+ end
79
+
80
+ def compute_dominant_cycle
81
+ p0.smooth = wma :input
82
+ p0.detrend = hilbert_transform :smooth, period: p1.period
83
+
84
+ # { Compute Inphase and Quadrature components }
85
+ p0.q1 = hilbert_transform :detrend, period: p1.period
86
+ p0.i1 = p3.detrend
87
+
88
+ # { Advance the phase of I1 and Q1 by 90 degrees }
89
+ p0.ji = hilbert_transform :i1, period: p1.period
90
+ p0.jq = hilbert_transform :q1, period: p1.period
91
+
92
+ # { Smooth the I and Q components before applying the discriminator }
93
+ p0.i2 = (0.2 * (p0.i1 - p0.jq)) + 0.8 * (p1.i2 || (p0.i1 - p0.jq))
94
+ p0.q2 = (0.2 * (p0.q1 + p0.ji)) + 0.8 * (p1.q2 || (p0.q1 + p0.ji))
95
+
96
+ homodyne_discriminator
97
+ end
98
+
99
+ def fast_limit
100
+ @fast_limit ||= bars_to_alpha(min_period / 2)
101
+ end
102
+
103
+ def slow_limit
104
+ @slow_limit ||= bars_to_alpha(max_period)
105
+ end
106
+
107
+ def compute_dominant_cycle_phase
108
+ p0.delta_phase = p1.phase - p0.phase
109
+ p0.delta_phase = 1.0 if p0.delta_phase < 1.0
110
+ end
111
+
112
+ FAMA = 0.500
113
+ GAMA = 0.950
114
+ DAMA = 0.125
115
+ LAMA = 0.100
116
+ FAGA = 0.050
117
+
118
+ def compute_moving_averages
119
+ alpha = [fast_limit / p0.delta_phase, slow_limit].max
120
+ p0.mama = (alpha * p0.input) + ((1.0 - alpha) * p1.mama)
121
+
122
+ p0.fama = (FAMA * alpha * p0.mama) + ((1.0 - (FAMA * alpha)) * p1.fama)
123
+ p0.gama = (GAMA * alpha * p0.mama) + ((1.0 - (GAMA * alpha)) * p1.gama)
124
+ p0.dama = (DAMA * alpha * p0.mama) + ((1.0 - (DAMA * alpha)) * p1.dama)
125
+ p0.lama = (LAMA * alpha * p0.mama) + ((1.0 - (LAMA * alpha)) * p1.lama)
126
+ p0.faga = (FAGA * alpha * p0.fama) + ((1.0 - (FAGA * alpha)) * p1.faga)
127
+ end
128
+
129
+ def compute_oscillator
130
+ p0.osc = p0.mama - p0.fama
131
+ p0.crossed = :up if p0.osc >= 0 && p1.osc < 0
132
+ p0.crossed = :down if p0.osc <= 0 && p1.osc > 0
133
+ end
134
+
135
+ def compute
136
+ compute_dominant_cycle
137
+ compute_dominant_cycle_phase
138
+ compute_moving_averages
139
+ compute_oscillator
140
+ end
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Quant
4
+ class Indicators
5
+ # The MESA inidicator
6
+ class MesaPoint < IndicatorPoint
7
+ attribute :mama, default: :input
8
+ attribute :fama, default: :input
9
+ attribute :dama, default: :input
10
+ attribute :gama, default: :input
11
+ attribute :lama, default: :input
12
+ attribute :faga, default: :input
13
+ attribute :osc, default: 0.0
14
+ attribute :crossed, default: :unchanged
15
+
16
+ def crossed_up?
17
+ @crossed == :up
18
+ end
19
+
20
+ def crossed_down?
21
+ @crossed == :down
22
+ end
23
+ end
24
+
25
+ # https://www.mesasoftware.com/papers/MAMA.pdf
26
+ # MESA Adaptive Moving Average (MAMA) adapts to price movement in an
27
+ # entirely new and unique way. The adapation is based on the rate change
28
+ # of phase as measured by the Hilbert Transform Discriminator.
29
+ #
30
+ # This version of Ehler's MAMA indicator ties into the homodyne
31
+ # dominant cycle indicator to provide a more efficient computation
32
+ # for this indicator. If you're using the homodyne in all your
33
+ # indicators for the dominant cycle, then this version is useful
34
+ # as it avoids extra computational steps.
35
+ class Mesa < Indicator
36
+ def period
37
+ dc_period
38
+ end
39
+
40
+ def fast_limit
41
+ @fast_limit ||= bars_to_alpha(min_period / 2)
42
+ end
43
+
44
+ def slow_limit
45
+ @slow_limit ||= bars_to_alpha(max_period)
46
+ end
47
+
48
+ def homodyne_dominant_cycle
49
+ series.indicators[source].dominant_cycles.homodyne
50
+ end
51
+
52
+ def current_dominant_cycle
53
+ homodyne_dominant_cycle.points[t0]
54
+ end
55
+
56
+ def delta_phase
57
+ current_dominant_cycle.delta_phase
58
+ end
59
+
60
+ FAMA = 0.500
61
+ GAMA = 0.950
62
+ DAMA = 0.125
63
+ LAMA = 0.100
64
+ FAGA = 0.050
65
+
66
+ def compute
67
+ alpha = [fast_limit / delta_phase, slow_limit].max
68
+
69
+ p0.mama = (alpha * p0.input) + ((1.0 - alpha) * p1.mama)
70
+ p0.fama = (FAMA * alpha * p0.mama) + ((1.0 - (FAMA * alpha)) * p1.fama)
71
+ p0.gama = (GAMA * alpha * p0.mama) + ((1.0 - (GAMA * alpha)) * p1.gama)
72
+ p0.dama = (DAMA * alpha * p0.mama) + ((1.0 - (DAMA * alpha)) * p1.dama)
73
+ p0.lama = (LAMA * alpha * p0.mama) + ((1.0 - (LAMA * alpha)) * p1.lama)
74
+ p0.faga = (FAGA * alpha * p0.fama) + ((1.0 - (FAGA * alpha)) * p1.faga)
75
+
76
+ compute_oscillator
77
+ end
78
+
79
+ def compute_oscillator
80
+ p0.osc = p0.mama - p0.fama
81
+ p0.crossed = :up if p0.osc >= 0 && p1.osc < 0
82
+ p0.crossed = :down if p0.osc <= 0 && p1.osc > 0
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,107 @@
1
+ module Quant
2
+ class Indicators
3
+ class PivotPoint < IndicatorPoint
4
+ attribute :high_price
5
+ attribute :avg_high, default: :high_price
6
+ attribute :highest, default: :input
7
+
8
+ attribute :low_price
9
+ attribute :avg_low, default: :low_price
10
+ attribute :lowest, default: :input
11
+
12
+ attribute :range, default: 0.0
13
+ attribute :avg_range, default: 0.0
14
+ attribute :std_dev, default: 0.0
15
+
16
+ def bands
17
+ @bands ||= { 0 => input }
18
+ end
19
+
20
+ def [](band)
21
+ bands[band]
22
+ end
23
+
24
+ def []=(band, value)
25
+ bands[band] = value
26
+ end
27
+
28
+ def key?(band)
29
+ bands.key?(band)
30
+ end
31
+
32
+ def midpoint
33
+ bands[0]
34
+ end
35
+ alias :h0 :midpoint
36
+ alias :l0 :midpoint
37
+
38
+ def midpoint=(value)
39
+ bands[0] = value
40
+ end
41
+ alias :h0= :midpoint=
42
+ alias :l0= :midpoint=
43
+
44
+ (1..8).each do |band|
45
+ define_method("h#{band}") { bands[band] }
46
+ define_method("h#{band}=") { |value| bands[band] = value }
47
+
48
+ define_method("l#{band}") { bands[-band] }
49
+ define_method("l#{band}=") { |value| bands[-band] = value }
50
+ end
51
+ end
52
+
53
+ class Pivot < Indicator
54
+ def points_class
55
+ Quant::Indicators::PivotPoint
56
+ end
57
+
58
+ def band?(band)
59
+ p0.key?(band)
60
+ end
61
+
62
+ def period
63
+ dc_period
64
+ end
65
+
66
+ def averaging_period
67
+ min_period
68
+ end
69
+
70
+ def period_midpoints
71
+ period_points(period).map(&:midpoint)
72
+ end
73
+
74
+ def compute
75
+ compute_extents
76
+ compute_value
77
+ compute_midpoint
78
+ compute_bands
79
+ end
80
+
81
+ def compute_midpoint
82
+ p0.midpoint = p0.input
83
+ end
84
+
85
+ def compute_value
86
+ # No-op -- override in subclasses
87
+ end
88
+
89
+ def compute_bands
90
+ # No-op -- override in subclasses
91
+ end
92
+
93
+ def compute_extents
94
+ period_midpoints.tap do |midpoints|
95
+ p0.high_price = t0.high_price
96
+ p0.low_price = t0.low_price
97
+ p0.highest = midpoints.max
98
+ p0.lowest = midpoints.min
99
+ p0.range = p0.high_price - p0.low_price
100
+ p0.avg_low = super_smoother(:low_price, previous: :avg_low, period: averaging_period)
101
+ p0.avg_high = super_smoother(:high_price, previous: :avg_high, period: averaging_period)
102
+ p0.avg_range = super_smoother(:range, previous: :avg_range, period: averaging_period)
103
+ end
104
+ end
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,41 @@
1
+ module Quant
2
+ class Indicators
3
+ class Pivots
4
+ class Atr < Pivot
5
+ depends_on Indicators::Atr
6
+
7
+ def atr_point
8
+ series.indicators[source].atr.points[t0]
9
+ end
10
+
11
+ def scale
12
+ 5.0
13
+ end
14
+
15
+ def atr_value
16
+ atr_point.slow * scale
17
+ end
18
+
19
+ def compute_midpoint
20
+ p0.midpoint = two_pole_super_smooth :input, previous: :midpoint, period: averaging_period
21
+ end
22
+
23
+ def compute_bands
24
+ p0.h6 = p0.midpoint + 1.000 * atr_value
25
+ p0.h5 = p0.midpoint + 0.786 * atr_value
26
+ p0.h4 = p0.midpoint + 0.618 * atr_value
27
+ p0.h3 = p0.midpoint + 0.500 * atr_value
28
+ p0.h2 = p0.midpoint + 0.382 * atr_value
29
+ p0.h1 = p0.midpoint + 0.236 * atr_value
30
+
31
+ p0.l1 = p0.midpoint - 0.236 * atr_value
32
+ p0.l2 = p0.midpoint - 0.382 * atr_value
33
+ p0.l3 = p0.midpoint - 0.500 * atr_value
34
+ p0.l4 = p0.midpoint - 0.618 * atr_value
35
+ p0.l5 = p0.midpoint - 0.786 * atr_value
36
+ p0.l6 = p0.midpoint - 1.000 * atr_value
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Quant
4
+ class Indicators
5
+ class Pivots
6
+ class Bollinger < Pivot
7
+ using Quant
8
+
9
+ def compute_midpoint
10
+ values = period_points(half_period).map(&:input)
11
+ alpha = bars_to_alpha(half_period)
12
+
13
+ p0.midpoint = alpha * values.mean + (1 - alpha) * p1.midpoint
14
+ p0.std_dev = values.standard_deviation(p0.midpoint)
15
+ end
16
+
17
+ def compute_bands
18
+ p0.h1 = p0.midpoint + p0.std_dev * 1.0
19
+ p0.l1 = p0.midpoint - p0.std_dev * 1.0
20
+
21
+ p0.h2 = p0.midpoint + p0.std_dev * 1.5
22
+ p0.l2 = p0.midpoint - p0.std_dev * 1.5
23
+
24
+ p0.h3 = p0.midpoint + p0.std_dev * 1.75
25
+ p0.l3 = p0.midpoint - p0.std_dev * 1.75
26
+
27
+ p0.h4 = p0.midpoint + p0.std_dev * 2.0
28
+ p0.l4 = p0.midpoint - p0.std_dev * 2.0
29
+
30
+ p0.h5 = p0.midpoint + p0.std_dev * 2.25
31
+ p0.l5 = p0.midpoint - p0.std_dev * 2.25
32
+
33
+ p0.h6 = p0.midpoint + p0.std_dev * 2.5
34
+ p0.l6 = p0.midpoint - p0.std_dev * 2.5
35
+
36
+ p0.h7 = p0.midpoint + p0.std_dev * 2.75
37
+ p0.l7 = p0.midpoint - p0.std_dev * 2.75
38
+
39
+ p0.h8 = p0.midpoint + p0.std_dev * 3.0
40
+ p0.l8 = p0.midpoint - p0.std_dev * 3.0
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Quant
4
+ class Indicators
5
+ class Pivots
6
+ # Camarilla pivot point calculations are rather straightforward. We need to
7
+ # input the previous day’s open, high, low and close. The formulas for each
8
+ # resistance and support level are:
9
+ #
10
+ # R4 = Close + (High – Low) * 1.1/2
11
+ # R3 = Close + (High – Low) * 1.1/4
12
+ # R2 = Close + (High – Low) * 1.1/6
13
+ # R1 = Close + (High – Low) * 1.1/12
14
+ # S1 = Close – (High – Low) * 1.1/12
15
+ # S2 = Close – (High – Low) * 1.1/6
16
+ # S3 = Close – (High – Low) * 1.1/4
17
+ # S4 = Close – (High – Low) * 1.1/2
18
+ #
19
+ # The calculation for further resistance and support levels varies from this
20
+ # norm. These levels can come into play during strong trend moves, so it’s
21
+ # important to understand how to identify them. For example, R5, R6, S5 and S6
22
+ # are calculated as follows:
23
+ #
24
+ # R5 = R4 + 1.168 * (R4 – R3)
25
+ # R6 = (High/Low) * Close
26
+ #
27
+ # S5 = S4 – 1.168 * (S3 – S4)
28
+ # S6 = Close – (R6 – Close)
29
+ class Camarilla < Pivot
30
+ def multiplier
31
+ 1.1
32
+ end
33
+
34
+ def compute_midpoint
35
+ p0.midpoint = t0.close_price
36
+ end
37
+
38
+ def compute_bands
39
+ mp_plus_range = p0.midpoint + p0.range
40
+ mp_minus_range = p0.midpoint - p0.range
41
+
42
+ p0.h4 = mp_plus_range * (1.1 / 2.0)
43
+ p0.h3 = mp_plus_range * (1.1 / 4.0)
44
+ p0.h2 = mp_plus_range * (1.1 / 6.0)
45
+ p0.h1 = mp_plus_range * (1.1 / 12.0)
46
+
47
+ p0.l1 = mp_minus_range * (1.1 / 12.0)
48
+ p0.l2 = mp_minus_range * (1.1 / 6.0)
49
+ p0.l3 = mp_minus_range * (1.1 / 4.0)
50
+ p0.l4 = mp_minus_range * (1.1 / 2.0)
51
+
52
+ p0.h5 = p0.h4 + 1.168 * (p0.h4 - p0.h3)
53
+ p0.h6 = p0.midpoint * (p0.high_price / p0.low_price)
54
+
55
+ p0.l5 = p0.l4 - 1.168 * (p0.l3 - p0.l4)
56
+ p0.l6 = p0.midpoint - (p0.h6 - p0.midpoint)
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Quant
4
+ class Indicators
5
+ class Pivots
6
+ class Classic < Pivot
7
+ def compute_midpoint
8
+ p0.midpoint = super_smoother :input, previous: :midpoint, period: averaging_period
9
+ end
10
+
11
+ def compute_bands
12
+ p0.h1 = p0.midpoint * 2.0 - p0.avg_low
13
+ p0.l1 = p0.midpoint * 2.0 - p0.avg_high
14
+
15
+ p0.h2 = p0.midpoint + p0.avg_range
16
+ p0.l2 = p0.midpoint - p0.avg_range
17
+
18
+ p0.h3 = p0.midpoint + 2.0 * p0.avg_range
19
+ p0.l3 = p0.midpoint - 2.0 * p0.avg_range
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Quant
4
+ class Indicators
5
+ class Pivots
6
+ # The value of X in the formula below depends on where the Close of the market is.
7
+ # If Close = Open then X = (H + L + (C * 2))
8
+
9
+ # If Close > Open then X = ((H * 2) + L + C)
10
+
11
+ # If Close < Open then X = (H + (L * 2) + C)
12
+
13
+ # R1 = X / 2 - L
14
+ # PP = X / 4 (this is not an official DeMark number but merely a reference point based on the calculation of X)
15
+ # S1 = X / 2 - H
16
+ class Demark < Pivot
17
+ def averaging_period
18
+ min_period / 2
19
+ end
20
+
21
+ def x_factor
22
+ if t0.close_price == t0.open_price
23
+ ((2.0 * t0.close_price) + p0.avg_high + p0.avg_low)
24
+ elsif t0.close_price > t0.open_price
25
+ ((2.0 * p0.avg_high) + p0.avg_low + t0.close_price)
26
+ else
27
+ ((2.0 * p0.avg_low) + p0.avg_high + t0.close_price)
28
+ end
29
+ end
30
+
31
+ def compute_value
32
+ p0.input = x_factor
33
+ end
34
+
35
+ def compute_midpoint
36
+ p0.midpoint = p0.input / 4.0
37
+ p0.midpoint = super_smoother :midpoint, previous: :midpoint, period: averaging_period
38
+ end
39
+
40
+ def compute_bands
41
+ p0.h1 = (p0.input / 2.0) - p0.avg_high
42
+ p0.h1 = super_smoother :h1, previous: :h1, period: averaging_period
43
+
44
+ p0.l1 = (p0.input / 2.0) - p0.avg_low
45
+ p0.l1 = super_smoother :l1, previous: :l1, period: averaging_period
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Quant
4
+ class Indicators
5
+ class Pivots
6
+ class Donchian < Pivot
7
+ using Quant
8
+
9
+ def st_period; min_period end
10
+ def mt_period; half_period end
11
+ def lt_period; max_period end
12
+
13
+ def st_highs; @st_highs ||= [].max_size!(st_period) end
14
+ def st_lows; @st_lows ||= [].max_size!(st_period) end
15
+ def mt_highs; @mt_highs ||= [].max_size!(mt_period) end
16
+ def mt_lows; @mt_lows ||= [].max_size!(mt_period) end
17
+ def lt_highs; @lt_highs ||= [].max_size!(lt_period) end
18
+ def lt_lows; @lt_lows ||= [].max_size!(lt_period) end
19
+
20
+ def compute_bands
21
+ st_highs << p0.high_price
22
+ st_lows << p0.low_price
23
+ mt_highs << p0.high_price
24
+ mt_lows << p0.low_price
25
+ lt_highs << p0.high_price
26
+ lt_lows << p0.low_price
27
+
28
+ p0.h1 = @st_highs.maximum
29
+ p0.l1 = @st_lows.minimum
30
+
31
+ p0.h2 = @mt_highs.maximum
32
+ p0.l2 = @mt_lows.minimum
33
+
34
+ p0.h3 = @lt_highs.maximum
35
+ p0.l3 = @lt_lows.minimum
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end