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.



135
136
137
# File 'lib/quant/indicators/indicator.rb', line 135

def p0
  @p0
end

#p1Object (readonly)

Returns the value of attribute p1.



135
136
137
# File 'lib/quant/indicators/indicator.rb', line 135

def p1
  @p1
end

#p2Object (readonly)

Returns the value of attribute p2.



135
136
137
# File 'lib/quant/indicators/indicator.rb', line 135

def p2
  @p2
end

#p3Object (readonly)

Returns the value of attribute p3.



135
136
137
# File 'lib/quant/indicators/indicator.rb', line 135

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.



136
137
138
# File 'lib/quant/indicators/indicator.rb', line 136

def t0
  @t0
end

#t1Object (readonly)

Returns the value of attribute t1.



136
137
138
# File 'lib/quant/indicators/indicator.rb', line 136

def t1
  @t1
end

#t2Object (readonly)

Returns the value of attribute t2.



136
137
138
# File 'lib/quant/indicators/indicator.rb', line 136

def t2
  @t2
end

#t3Object (readonly)

Returns the value of attribute t3.



136
137
138
# File 'lib/quant/indicators/indicator.rb', line 136

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



138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
# File 'lib/quant/indicators/indicator.rb', line 138

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



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

def [](index)
  values[index]
end

#adaptive_half_periodObject Also known as: dc_half_period, dominant_half_cycle_period



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

def adaptive_half_period
  adaptive_period / 2
end

#adaptive_periodObject Also known as: dc_period, dominant_cycle_period

The adaptive period is the full dominant cycle period



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

def adaptive_period
  dominant_cycle.points[t0].period
end

#computeObject

Raises:

  • (NotImplementedError)


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

def compute
  raise NotImplementedError
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



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

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



166
167
168
# File 'lib/quant/indicators/indicator.rb', line 166

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)


201
202
203
# File 'lib/quant/indicators/indicator.rb', line 201

def input
  t0.send(source)
end

#inspectObject



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

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)


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

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



130
131
132
133
# File 'lib/quant/indicators/indicator.rb', line 130

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



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

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



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

def size
  @points.size
end

#t(offset) ⇒ Object

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

Raises:

  • (ArgumentError)


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

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

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

#ticksObject



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

def ticks
  @points.keys
end

#valuesObject



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

def values
  @points.values
end

#warmed_up?Boolean

Returns:

  • (Boolean)


205
206
207
# File 'lib/quant/indicators/indicator.rb', line 205

def warmed_up?
  ticks.size > min_period
end