Class: Quant::Indicators::Indicator

Inherits:
Object
  • Object
show all
Includes:
Enumerable, Mixins::Filters, Mixins::FisherTransform, Mixins::Functions, Mixins::HilbertTransform, Mixins::MovingAverages, Mixins::Stochastic, Mixins::SuperSmoother
Defined in:
lib/quant/indicators/indicator.rb

Overview

The Indicator class is the abstract ancestor for all Indicators.

Constant Summary collapse

PRIORITIES =

The priority drives the order of computations when iterating over each tick in a series. Generally speaking, indicators that feed values to another indicator must have a lower priority value than the indicator that consumes the values.

* Most indicators will have a default priority of 1000.
* Dominant Cycle indicators will have a priority of 100.
* Some indicators will have a "high priority" of 500.

Priority values are arbitrary and purposefully gapping so that new indicators introduced outside the core library can be slotted in between.

NOTE: Priority is well-managed by the library and should not require overriding for a custom indicator developed outside the library. If you find yourself needing to override this method, please open an issue on the library’s GitHub page.

[
  DOMINANT_CYCLES_PRIORITY = 100,
  DEPENDENCY_PRIORITY = 500,
  DEFAULT_PRIORITY = 1000
].freeze

Constants included from Mixins::UniversalFilters

Mixins::UniversalFilters::K

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Mixins::FisherTransform

#fisher_transform, #inverse_fisher_transform, #relative_fisher_transform

Methods included from Mixins::Stochastic

#stochastic

Methods included from Mixins::SuperSmoother

#three_pole_super_smooth, #two_pole_super_smooth

Methods included from Mixins::HilbertTransform

#hilbert_transform

Methods included from Mixins::ExponentialMovingAverage

#exponential_moving_average

Methods included from Mixins::SimpleMovingAverage

#simple_moving_average

Methods included from Mixins::WeightedMovingAverage

#extended_weighted_moving_average, #weighted_moving_average

Methods included from Mixins::UniversalFilters

#universal_band_pass, #universal_ema, #universal_filter, #universal_one_pole_high_pass, #universal_one_pole_low_pass, #universal_two_pole_high_pass, #universal_two_pole_low_pass

Methods included from Mixins::ButterworthFilters

#three_pole_butterworth, #two_pole_butterworth

Methods included from Mixins::HighPassFilters

#high_pass_filter, #hpf2, #two_pole_high_pass_filter

Methods included from Mixins::Functions

#angle, #bars_to_alpha, #deg2rad, #period_to_alpha, #rad2deg

Constructor Details

#initialize(series:, source:) ⇒ Indicator

Returns a new instance of Indicator.



40
41
42
43
44
45
# File 'lib/quant/indicators/indicator.rb', line 40

def initialize(series:, source:)
  @series = series
  @source = source
  @points = {}
  series.each { |tick| self << tick }
end

Instance Attribute Details

#p0Object (readonly)

Returns the value of attribute p0.



126
127
128
# File 'lib/quant/indicators/indicator.rb', line 126

def p0
  @p0
end

#p1Object (readonly)

Returns the value of attribute p1.



126
127
128
# File 'lib/quant/indicators/indicator.rb', line 126

def p1
  @p1
end

#p2Object (readonly)

Returns the value of attribute p2.



126
127
128
# File 'lib/quant/indicators/indicator.rb', line 126

def p2
  @p2
end

#p3Object (readonly)

Returns the value of attribute p3.



126
127
128
# File 'lib/quant/indicators/indicator.rb', line 126

def p3
  @p3
end

#seriesObject (readonly)

Returns the value of attribute series.



38
39
40
# File 'lib/quant/indicators/indicator.rb', line 38

def series
  @series
end

#sourceObject (readonly)

Returns the value of attribute source.



38
39
40
# File 'lib/quant/indicators/indicator.rb', line 38

def source
  @source
end

#t0Object (readonly)

Returns the value of attribute t0.



127
128
129
# File 'lib/quant/indicators/indicator.rb', line 127

def t0
  @t0
end

#t1Object (readonly)

Returns the value of attribute t1.



127
128
129
# File 'lib/quant/indicators/indicator.rb', line 127

def t1
  @t1
end

#t2Object (readonly)

Returns the value of attribute t2.



127
128
129
# File 'lib/quant/indicators/indicator.rb', line 127

def t2
  @t2
end

#t3Object (readonly)

Returns the value of attribute t3.



127
128
129
# File 'lib/quant/indicators/indicator.rb', line 127

def t3
  @t3
end

Class Method Details

.dependent_indicator_classesObject

Provides a registry of dependent indicators for each indicator class. NOTE: Internal use only.



24
25
26
# File 'lib/quant/indicators/indicator.rb', line 24

def self.dependent_indicator_classes
  @dependent_indicator_classes ||= Set.new
end

.depends_on(*indicator_classes) ⇒ Object

Use the depends_on method to declare dependencies for an indicator.

Examples:

class BarIndicator < Indicator
  depends_on FooIndicator
end

Parameters:

  • indicator_classes (Array<Class>)

    The classes of the indicators to depend on.



34
35
36
# File 'lib/quant/indicators/indicator.rb', line 34

def self.depends_on(*indicator_classes)
  Array(indicator_classes).each{ |dependency| dependent_indicator_classes << dependency }
end

.register(name:) ⇒ Object

include Mixins::Direction



18
19
20
# File 'lib/quant/indicators/indicator.rb', line 18

def self.register(name:)
  Quant::IndicatorsSource.register(name:, indicator_class: self)
end

Instance Method Details

#<<(tick) ⇒ Object



129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/quant/indicators/indicator.rb', line 129

def <<(tick)
  @t0 = tick
  @p0 = points_class.new(indicator: self, tick:, source:)
  @points[tick] = @p0

  @p1 = values[-2] || @p0
  @p2 = values[-3] || @p1
  @p3 = values[-4] || @p2

  @t1 = ticks[-2] || @t0
  @t2 = ticks[-3] || @t1
  @t3 = ticks[-4] || @t2

  compute
end

#[](index) ⇒ Object



109
110
111
# File 'lib/quant/indicators/indicator.rb', line 109

def [](index)
  values[index]
end

#computeObject

Raises:

  • (NotImplementedError)


153
154
155
# File 'lib/quant/indicators/indicator.rb', line 153

def compute
  raise NotImplementedError
end

#dc_periodObject



101
102
103
# File 'lib/quant/indicators/indicator.rb', line 101

def dc_period
  dominant_cycle.points[t0].period
end

#dominant_cycleObject



97
98
99
# File 'lib/quant/indicators/indicator.rb', line 97

def dominant_cycle
  series.indicators[source][dominant_cycle_indicator_class]
end

#dominant_cycle_indicator_classObject



47
48
49
# File 'lib/quant/indicators/indicator.rb', line 47

def dominant_cycle_indicator_class
  Quant.config.indicators.dominant_cycle_indicator_class
end

#dominant_cycle_kindObject



89
90
91
# File 'lib/quant/indicators/indicator.rb', line 89

def dominant_cycle_kind
  Quant.config.indicators.dominant_cycle_kind
end

#each(&block) ⇒ Object



145
146
147
# File 'lib/quant/indicators/indicator.rb', line 145

def each(&block)
  @points.each_value(&block)
end

#half_periodObject



81
82
83
# File 'lib/quant/indicators/indicator.rb', line 81

def half_period
  Quant.config.indicators.half_period
end

#indicator_nameObject



157
158
159
# File 'lib/quant/indicators/indicator.rb', line 157

def indicator_name
  self.class.name.split("::").last
end

#inputNumeric

The input is the value derived from the source for the indicator for the current tick. For example, if the source is :oc2, then the input is the value of the current tick’s (open + close) / 2

Returns:

  • (Numeric)


192
193
194
# File 'lib/quant/indicators/indicator.rb', line 192

def input
  t0.send(source)
end

#inspectObject



149
150
151
# File 'lib/quant/indicators/indicator.rb', line 149

def inspect
  "#<#{self.class.name} symbol=#{series.symbol} source=#{source} ticks=#{ticks.size}>"
end

#max_periodObject



77
78
79
# File 'lib/quant/indicators/indicator.rb', line 77

def max_period
  Quant.config.indicators.max_period
end

#micro_periodObject



85
86
87
# File 'lib/quant/indicators/indicator.rb', line 85

def micro_period
  Quant.config.indicators.micro_period
end

#min_periodObject



73
74
75
# File 'lib/quant/indicators/indicator.rb', line 73

def min_period
  Quant.config.indicators.min_period
end

#p(offset) ⇒ Object

p(0) => values p(1) => values p(2) => values p(3) => values

Raises:

  • (ArgumentError)


169
170
171
172
173
174
# File 'lib/quant/indicators/indicator.rb', line 169

def p(offset)
  raise ArgumentError, "offset must be a positive value" if offset < 0

  index = offset + 1
  values[[-index, -size].max]
end

#period_points(max_period) ⇒ Object



121
122
123
124
# File 'lib/quant/indicators/indicator.rb', line 121

def period_points(max_period)
  extent = [values.size, max_period].min
  values[-extent, extent]
end

#pivot_kindObject



93
94
95
# File 'lib/quant/indicators/indicator.rb', line 93

def pivot_kind
  Quant.config.indicators.pivot_kind
end

#points_classObject



161
162
163
# File 'lib/quant/indicators/indicator.rb', line 161

def points_class
  Object.const_get "Quant::Indicators::#{indicator_name}Point"
end

#priorityObject



69
70
71
# File 'lib/quant/indicators/indicator.rb', line 69

def priority
  DEFAULT_PRIORITY
end

#sizeObject



117
118
119
# File 'lib/quant/indicators/indicator.rb', line 117

def size
  @points.size
end

#t(offset) ⇒ Object

t(0) => ticks t(1) => ticks t(2) => ticks t(3) => ticks

Raises:

  • (ArgumentError)


180
181
182
183
184
185
# File 'lib/quant/indicators/indicator.rb', line 180

def t(offset)
  raise ArgumentError, "offset must be a positive value" if offset < 0

  index = offset + 1
  ticks[[-index, -size].max]
end

#ticksObject



105
106
107
# File 'lib/quant/indicators/indicator.rb', line 105

def ticks
  @points.keys
end

#valuesObject



113
114
115
# File 'lib/quant/indicators/indicator.rb', line 113

def values
  @points.values
end