quantitative 0.1.4 → 0.1.5
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 +4 -4
- data/Gemfile.lock +1 -1
- data/lib/quant/asset.rb +88 -0
- data/lib/quant/{security_class.rb → asset_class.rb} +14 -14
- data/lib/quant/attributes.rb +134 -0
- data/lib/quant/errors.rb +30 -5
- data/lib/quant/indicators/indicator.rb +87 -52
- data/lib/quant/indicators/indicator_point.rb +9 -21
- data/lib/quant/indicators/ma.rb +12 -20
- data/lib/quant/indicators/ping.rb +16 -0
- data/lib/quant/indicators.rb +1 -23
- data/lib/quant/indicators_proxy.rb +23 -0
- data/lib/quant/indicators_sources.rb +18 -0
- data/lib/quant/interval.rb +37 -12
- data/lib/quant/mixins/filters.rb +2 -0
- data/lib/quant/refinements/array.rb +8 -7
- data/lib/quant/series.rb +36 -19
- data/lib/quant/ticks/ohlc.rb +7 -10
- data/lib/quant/ticks/serializers/ohlc.rb +33 -22
- data/lib/quant/ticks/serializers/spot.rb +1 -4
- data/lib/quant/ticks/serializers/tick.rb +3 -3
- data/lib/quant/ticks/spot.rb +7 -7
- data/lib/quant/ticks/tick.rb +22 -9
- data/lib/quant/version.rb +1 -1
- data/lib/quantitative.rb +1 -1
- metadata +8 -4
- data/lib/quant/security.rb +0 -80
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c9fa0c537499409fa9faa3fbca76beca44d37205c04c8de1c01b3e681985c2dc
|
4
|
+
data.tar.gz: 3916820207b47d2d19b79332e41329c35080ce1456c4a2ed751863ea220b5289
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e3bead0b7fc23208c62dd18bb8f701b684db20780ae793fab973ab07cea0740897026a66755a07b9857228e815bfc3679801171f2b5875f510a7c98781fd30cb
|
7
|
+
data.tar.gz: 8b07dbcbe1a86c507a31df950aef293ae018913964848a9298310fe71a7929924a5a7ced417cf5ef86e9282feb58bc9d16531bf6b77e0fa23cea28de7a761740
|
data/Gemfile.lock
CHANGED
data/lib/quant/asset.rb
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "asset_class"
|
4
|
+
|
5
|
+
module Quant
|
6
|
+
# A {Quant::Asset} is a representation of a financial instrument such as a stock, option, future, or currency.
|
7
|
+
# It is used to represent the instrument that is being traded, analyzed, or managed.
|
8
|
+
#
|
9
|
+
# Not all data sources have a rich set of attributes for their assets or securities. The {Quant::Asset} is designed
|
10
|
+
# to be flexible and to support a wide variety of data sources and use-cases. The most common use-cases are supported
|
11
|
+
# while allowing for additional attributes to be added via the +meta+ attribute, which is tyipically just a Hash,
|
12
|
+
# but can be any object that can hold useful information about the asset such as currency formatting, precision, etc.
|
13
|
+
# @example
|
14
|
+
# asset = Quant::Asset.new(symbol: "AAPL", name: "Apple Inc.", asset_class: :stock, exchange: "NASDAQ")
|
15
|
+
# asset.symbol # => "AAPL"
|
16
|
+
# asset.name # => "Apple Inc."
|
17
|
+
# asset.stock? # => true
|
18
|
+
# asset.option? # => false
|
19
|
+
# asset.future? # => false
|
20
|
+
# asset.currency? # => false
|
21
|
+
# asset.exchange # => "NASDAQ"
|
22
|
+
#
|
23
|
+
# # Can serialize two ways:
|
24
|
+
# asset.to_h # => { "s" => "AAPL" }
|
25
|
+
# asset.to_h(full: true) # => { "s" => "AAPL", "n" => "Apple Inc.", "sc" => "stock", "x" => "NASDAQ" }
|
26
|
+
class Asset
|
27
|
+
attr_reader :symbol, :name, :asset_class, :id, :exchange, :source, :meta, :created_at, :updated_at
|
28
|
+
|
29
|
+
def initialize(
|
30
|
+
symbol:,
|
31
|
+
name: nil,
|
32
|
+
id: nil,
|
33
|
+
active: true,
|
34
|
+
tradeable: true,
|
35
|
+
exchange: nil,
|
36
|
+
source: nil,
|
37
|
+
asset_class: nil,
|
38
|
+
created_at: Quant.current_time,
|
39
|
+
updated_at: Quant.current_time,
|
40
|
+
meta: {}
|
41
|
+
)
|
42
|
+
raise ArgumentError, "symbol is required" unless symbol
|
43
|
+
|
44
|
+
@symbol = symbol.to_s.upcase
|
45
|
+
@name = name
|
46
|
+
@id = id
|
47
|
+
@tradeable = tradeable
|
48
|
+
@active = active
|
49
|
+
@exchange = exchange
|
50
|
+
@source = source
|
51
|
+
@asset_class = AssetClass.new(asset_class)
|
52
|
+
@created_at = created_at
|
53
|
+
@updated_at = updated_at
|
54
|
+
@meta = meta
|
55
|
+
end
|
56
|
+
|
57
|
+
def active?
|
58
|
+
!!@active
|
59
|
+
end
|
60
|
+
|
61
|
+
def tradeable?
|
62
|
+
!!@tradeable
|
63
|
+
end
|
64
|
+
|
65
|
+
AssetClass::CLASSES.each do |class_name|
|
66
|
+
define_method("#{class_name}?") do
|
67
|
+
asset_class == class_name
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def to_h(full: false)
|
72
|
+
return { "s" => symbol } unless full
|
73
|
+
|
74
|
+
{ "s" => symbol,
|
75
|
+
"n" => name,
|
76
|
+
"id" => id,
|
77
|
+
"t" => tradeable?,
|
78
|
+
"a" => active?,
|
79
|
+
"x" => exchange,
|
80
|
+
"sc" => asset_class.to_s,
|
81
|
+
"src" => source.to_s }
|
82
|
+
end
|
83
|
+
|
84
|
+
def to_json(*args, full: false)
|
85
|
+
Oj.dump(to_h(full: full), *args)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -24,7 +24,7 @@ module Quant
|
|
24
24
|
# real estate. Investors can buy shares in a REIT, which provides them with a share of the
|
25
25
|
# income produced by the real estate.
|
26
26
|
|
27
|
-
# Cryptocurrencies: Digital or virtual currencies that use cryptography for
|
27
|
+
# Cryptocurrencies: Digital or virtual currencies that use cryptography for asset and operate on
|
28
28
|
# decentralized networks, typically based on blockchain technology. Examples include Bitcoin, Ethereum, and Ripple.
|
29
29
|
|
30
30
|
# Preferred Stock: A type of stock that has priority over common stock in terms of dividend
|
@@ -40,7 +40,7 @@ module Quant
|
|
40
40
|
|
41
41
|
# Foreign Exchange (Forex): The market where currencies are traded. Investors can buy and sell currencies to
|
42
42
|
# profit from changes in exchange rates.
|
43
|
-
class
|
43
|
+
class AssetClass
|
44
44
|
CLASSES = %i(
|
45
45
|
bond
|
46
46
|
commodity
|
@@ -57,31 +57,31 @@ module Quant
|
|
57
57
|
treasury_note
|
58
58
|
).freeze
|
59
59
|
|
60
|
-
attr_reader :
|
60
|
+
attr_reader :asset_class
|
61
61
|
|
62
62
|
def initialize(name)
|
63
|
-
return if @
|
63
|
+
return if @asset_class = from_standard(name)
|
64
64
|
|
65
|
-
@
|
66
|
-
|
65
|
+
@asset_class = from_alternate(name.to_s.downcase.to_sym) unless name.nil?
|
66
|
+
raise_unknown_asset_class_error(name) unless asset_class
|
67
67
|
end
|
68
68
|
|
69
69
|
CLASSES.each do |class_name|
|
70
70
|
define_method("#{class_name}?") do
|
71
|
-
|
71
|
+
asset_class == class_name
|
72
72
|
end
|
73
73
|
end
|
74
74
|
|
75
|
-
def
|
76
|
-
raise
|
75
|
+
def raise_unknown_asset_class_error(name)
|
76
|
+
raise Errors::AssetClassError, "Unknown asset class: #{name.inspect}"
|
77
77
|
end
|
78
78
|
|
79
79
|
def to_s
|
80
|
-
|
80
|
+
asset_class.to_s
|
81
81
|
end
|
82
82
|
|
83
83
|
def to_h
|
84
|
-
{ "sc" =>
|
84
|
+
{ "sc" => asset_class }
|
85
85
|
end
|
86
86
|
|
87
87
|
def to_json(*args)
|
@@ -90,9 +90,9 @@ module Quant
|
|
90
90
|
|
91
91
|
def ==(other)
|
92
92
|
case other
|
93
|
-
when String then from_alternate(other.to_sym) ==
|
94
|
-
when Symbol then from_alternate(other) ==
|
95
|
-
when
|
93
|
+
when String then from_alternate(other.to_sym) == asset_class
|
94
|
+
when Symbol then from_alternate(other) == asset_class
|
95
|
+
when AssetClass then other.asset_class == asset_class
|
96
96
|
else
|
97
97
|
false
|
98
98
|
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Quant
|
4
|
+
module Attributes
|
5
|
+
# Tracks all defined attributes, allowing child classes to inherit their parent's attributes.
|
6
|
+
# The registry key is the class registering an attrbritute and is itself a hash of the attribute name
|
7
|
+
# and the attribute's key and default value.
|
8
|
+
# Internal use only.
|
9
|
+
#
|
10
|
+
# @example
|
11
|
+
# { Quant::Indicators::IndicatorPoint => {
|
12
|
+
# tick: { key: nil, default: nil },
|
13
|
+
# source: { key: "src", default: nil },
|
14
|
+
# input: { key: "in", default: nil }
|
15
|
+
# },
|
16
|
+
# Quant::Indicators::PingPoint => {
|
17
|
+
# pong: { key: nil, default: nil },
|
18
|
+
# compute_count: { key: nil, default: 0 }
|
19
|
+
# }
|
20
|
+
# }
|
21
|
+
# @return [Hash] The registry of all defined attributes.
|
22
|
+
def self.registry
|
23
|
+
@registry ||= {}
|
24
|
+
end
|
25
|
+
|
26
|
+
# Removes the given class from the registry. Useful for testing.
|
27
|
+
def self.deregister(klass)
|
28
|
+
registry.delete(klass)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Registers an attribute for a class in the registry.
|
32
|
+
# Internal use only.
|
33
|
+
#
|
34
|
+
# @param klass [Class] The class registering the attribute
|
35
|
+
# @param name [Symbol] The name of the attribute
|
36
|
+
# @param key [String] The key to use when serializing the attribute
|
37
|
+
# @param default [Object] The default value for the attribute
|
38
|
+
def self.register(klass, name, key, default)
|
39
|
+
# Disallow redefining or replacing a key as it is easy to miss the overwrite
|
40
|
+
# and leads to serialization surprises.
|
41
|
+
if key && registry.values.flat_map(&:values).map{ |entry| entry[:key] }.include?(key)
|
42
|
+
raise Errors::DuplicateAttributesKeyError, "Attribute Key #{key} already defined!"
|
43
|
+
end
|
44
|
+
|
45
|
+
registry[klass] ||= {}
|
46
|
+
registry[klass][name] = { key: key, default: default }
|
47
|
+
end
|
48
|
+
|
49
|
+
module InstanceMethods
|
50
|
+
def initialize(...)
|
51
|
+
initialize_attributes
|
52
|
+
super(...)
|
53
|
+
end
|
54
|
+
|
55
|
+
# Iterates over all defined attributes in a child => parent hierarchy,
|
56
|
+
# and yields the name and entry for each.
|
57
|
+
def each_attribute(&block)
|
58
|
+
klass = self.class
|
59
|
+
loop do
|
60
|
+
attributes = Attributes.registry[klass]
|
61
|
+
break if attributes.nil?
|
62
|
+
|
63
|
+
attributes.each{ |name, entry| block.call(name, entry) }
|
64
|
+
klass = klass.superclass
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# Initializes the defined attributes with default values and
|
69
|
+
# defines accessor methods for each attribute.
|
70
|
+
# If a child class redefines a parent's attribute, the child's
|
71
|
+
# definition will be used.
|
72
|
+
def initialize_attributes
|
73
|
+
each_attribute do |name, entry|
|
74
|
+
# use the child's definition, skipping the parent's
|
75
|
+
next if respond_to?(name)
|
76
|
+
|
77
|
+
ivar_name = "@#{name}"
|
78
|
+
instance_variable_set(ivar_name, entry[:default])
|
79
|
+
define_singleton_method(name) { instance_variable_get(ivar_name) }
|
80
|
+
define_singleton_method("#{name}=") { |value| instance_variable_set(ivar_name, value) }
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# Serializes keys that have been defined as serializeable attributes
|
85
|
+
# Key values that are nil are removed from the hash
|
86
|
+
# @return [Hash] The serialized attributes as a Ruby Hash.
|
87
|
+
def to_h
|
88
|
+
{}.tap do |key_values|
|
89
|
+
each_attribute do |name, entry|
|
90
|
+
next unless entry[:key]
|
91
|
+
|
92
|
+
ivar_name = "@#{name}"
|
93
|
+
value = instance_variable_get(ivar_name)
|
94
|
+
|
95
|
+
key_values[entry[:key]] = value if value
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# Serializes keys that have been defined as serializeable attributes
|
101
|
+
# Key values that are nil are removed from the hash
|
102
|
+
# @return [String] The serialized attributes as a JSON string.
|
103
|
+
def to_json(*args)
|
104
|
+
Oj.dump(to_h, *args)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
module ClassMethods
|
109
|
+
# Define an +attribute+ for the class that can optionally be serialized.
|
110
|
+
# Works much like an attr_accessor does, but also manages serialization for
|
111
|
+
# #to_h and #to_json methods.
|
112
|
+
#
|
113
|
+
# An +attribute+ will result in a same-named instance on the class when
|
114
|
+
# it is instantiated and it will set a default value if one is provided.
|
115
|
+
#
|
116
|
+
# @param name [Symbol] The name of the attribute and it's accessor methods
|
117
|
+
# @param key [String] The key to use when serializing the attribute
|
118
|
+
# @param default [Object] The default value for the attribute
|
119
|
+
#
|
120
|
+
# @examples
|
121
|
+
# attribute :tick # will not serialize to a key
|
122
|
+
# attribute :source, key: "src" # serializes to "src" key
|
123
|
+
# attribute :input, key: "in" # serializes to "in" key
|
124
|
+
def attribute(name, key: nil, default: nil)
|
125
|
+
Attributes.register(self, name, key, default)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def self.included(base) # :nodoc:
|
130
|
+
base.extend(ClassMethods)
|
131
|
+
base.prepend(InstanceMethods)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
data/lib/quant/errors.rb
CHANGED
@@ -1,9 +1,34 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Quant
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
4
|
+
module Errors
|
5
|
+
# {Error} is the base class for all errors in the Quant gem.
|
6
|
+
# It is a subclass of the Ruby {StandardError}.
|
7
|
+
class Error < StandardError; end
|
8
|
+
|
9
|
+
# {InvalidInterval} is raised when attempting to instantiate an
|
10
|
+
# {Quant::Interval} with an invalid value.
|
11
|
+
class InvalidInterval < Error; end
|
12
|
+
|
13
|
+
# {InvalidResolution} is raised when attempting to instantiate
|
14
|
+
# an {Quant::Resolution} with a resolution value that has not been defined.
|
15
|
+
class InvalidResolution < Error; end
|
16
|
+
|
17
|
+
# {ArrayMaxSizeError} is raised when attempting to set the +max_size+ on
|
18
|
+
# the refined {Array} class to an invalid value or when attempting to
|
19
|
+
# redefine the +max_size+ on the refined {Array} class.
|
20
|
+
class ArrayMaxSizeError < Error; end
|
21
|
+
|
22
|
+
# {AssetClassError} is raised when attempting to instantiate a
|
23
|
+
# {Quant::Asset} with an attribute that is not a valid {Quant::Asset} attribute.
|
24
|
+
class AssetClassError < Error; end
|
25
|
+
|
26
|
+
# {DuplicateAttributesKeyError} is raised when attempting to define an
|
27
|
+
# attribute with a key that has already been defined.
|
28
|
+
class DuplicateAttributesKeyError < Error; end
|
29
|
+
|
30
|
+
# {DuplicateAttributesNameError} is raised when attempting to define an
|
31
|
+
# attribute with a name that has already been defined.
|
32
|
+
class DuplicateAttributesNameError < Error; end
|
33
|
+
end
|
9
34
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module Quant
|
2
2
|
class Indicators
|
3
3
|
class Indicator
|
4
|
-
|
4
|
+
include Enumerable
|
5
5
|
|
6
6
|
# # include Mixins::TrendMethods
|
7
7
|
# include Mixins::Trig
|
@@ -14,57 +14,103 @@ module Quant
|
|
14
14
|
# include Mixins::Direction
|
15
15
|
# include Mixins::Filters
|
16
16
|
|
17
|
-
|
18
|
-
# "#<#{self.class.name} #{symbol} #{interval} #{points.size} points>"
|
19
|
-
# end
|
17
|
+
attr_reader :source, :series
|
20
18
|
|
21
|
-
|
22
|
-
|
23
|
-
|
19
|
+
def initialize(series:, source:)
|
20
|
+
@series = series
|
21
|
+
@source = source
|
22
|
+
@points = {}
|
23
|
+
series.each { |tick| self << tick }
|
24
|
+
end
|
24
25
|
|
25
|
-
|
26
|
-
|
27
|
-
|
26
|
+
def ticks
|
27
|
+
@points.keys
|
28
|
+
end
|
28
29
|
|
29
|
-
|
30
|
-
|
31
|
-
|
30
|
+
def values
|
31
|
+
@points.values
|
32
|
+
end
|
32
33
|
|
33
|
-
|
34
|
-
|
35
|
-
|
34
|
+
def size
|
35
|
+
@points.size
|
36
|
+
end
|
36
37
|
|
37
|
-
|
38
|
-
|
39
|
-
# end
|
38
|
+
attr_reader :p0, :p1, :p2, :p3
|
39
|
+
attr_reader :t0, :t1, :t2, :t3
|
40
40
|
|
41
|
-
|
42
|
-
|
43
|
-
|
41
|
+
def <<(tick)
|
42
|
+
@t0 = tick
|
43
|
+
@p0 = points_class.new(tick: tick, source: source)
|
44
|
+
@points[tick] = @p0
|
44
45
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
# end
|
46
|
+
@p1 = values[-2] || @p0
|
47
|
+
@p2 = values[-3] || @p1
|
48
|
+
@p3 = values[-4] || @p2
|
49
49
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
# delegate :oc2, :high_price, :low_price, :open_price, :close_price, :volume, to: :p0
|
50
|
+
@t1 = ticks[-2] || @t0
|
51
|
+
@t2 = ticks[-3] || @t1
|
52
|
+
@t3 = ticks[-4] || @t2
|
54
53
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
54
|
+
compute
|
55
|
+
end
|
56
|
+
|
57
|
+
def each(&block)
|
58
|
+
@points.each_value(&block)
|
59
|
+
end
|
60
|
+
|
61
|
+
def inspect
|
62
|
+
"#<#{self.class.name} symbol=#{series.symbol} source=#{source} #{points.size} ticks>"
|
63
|
+
end
|
64
|
+
|
65
|
+
def compute
|
66
|
+
raise NotImplementedError
|
66
67
|
end
|
67
68
|
|
69
|
+
def indicator_name
|
70
|
+
self.class.name.split("::").last
|
71
|
+
end
|
72
|
+
|
73
|
+
def points_class
|
74
|
+
Object.const_get "Quant::Indicators::#{indicator_name}Point"
|
75
|
+
end
|
76
|
+
|
77
|
+
# p(0) => values[-1]
|
78
|
+
# p(1) => values[-2]
|
79
|
+
# p(2) => values[-3]
|
80
|
+
# p(3) => values[-4]
|
81
|
+
def p(offset)
|
82
|
+
raise ArgumentError, "offset must be a positive value" if offset < 0
|
83
|
+
|
84
|
+
index = offset + 1
|
85
|
+
values[[-index, -size].max]
|
86
|
+
end
|
87
|
+
|
88
|
+
# t(0) => ticks[-1]
|
89
|
+
# t(1) => ticks[-2]
|
90
|
+
# t(2) => ticks[-3]
|
91
|
+
# t(3) => ticks[-4]
|
92
|
+
def t(offset)
|
93
|
+
raise ArgumentError, "offset must be a positive value" if offset < 0
|
94
|
+
|
95
|
+
index = offset + 1
|
96
|
+
ticks[[-index, -size].max]
|
97
|
+
end
|
98
|
+
|
99
|
+
# The input is the value derived from the source for the indicator
|
100
|
+
# for the current tick.
|
101
|
+
# For example, if the source is :oc2, then the input is the
|
102
|
+
# value of the current tick's (open + close) / 2
|
103
|
+
# @return [Numeric]
|
104
|
+
def input
|
105
|
+
t0.send(source)
|
106
|
+
end
|
107
|
+
|
108
|
+
# def warmed_up?
|
109
|
+
# true
|
110
|
+
# end
|
111
|
+
|
112
|
+
# attr_reader :dc_period
|
113
|
+
|
68
114
|
# def points_for(series:)
|
69
115
|
# @points_for_cache[series] ||= self.class.new(series:, settings:, cloning: true).tap do |indicator|
|
70
116
|
# series.ticks.each { |tick| indicator.points.push(tick.indicators[self]) }
|
@@ -77,10 +123,6 @@ module Quant
|
|
77
123
|
# series.ticks.empty? ? series : series.ticks.first.series
|
78
124
|
# end
|
79
125
|
|
80
|
-
# def after_initialization
|
81
|
-
# # NoOp
|
82
|
-
# end
|
83
|
-
|
84
126
|
# # Returns the last point of the current indicator rather than the entire series
|
85
127
|
# # This is used for indicators that depend on dominant cycle or other indicators
|
86
128
|
# # to compute their data points.
|
@@ -103,13 +145,6 @@ module Quant
|
|
103
145
|
# raise 'Dominant Cycle Indicators cannot use the thing they compute!'
|
104
146
|
# end
|
105
147
|
|
106
|
-
# # Sets the dominant cycle period for the current indicator's point
|
107
|
-
# # @dc_period gets set before each #compute call.
|
108
|
-
# def update_dc_period
|
109
|
-
# ensure_not_dominant_cycler_indicator
|
110
|
-
# @dc_period = current_dominant_cycle.period
|
111
|
-
# end
|
112
|
-
|
113
148
|
# # Returns the dominant cycle point for the current indicator's point
|
114
149
|
# def current_dominant_cycle
|
115
150
|
# dominant_cycle_indicator[current_point]
|
@@ -3,33 +3,21 @@
|
|
3
3
|
module Quant
|
4
4
|
class Indicators
|
5
5
|
class IndicatorPoint
|
6
|
-
|
6
|
+
include Quant::Attributes
|
7
7
|
|
8
|
-
|
8
|
+
attribute :tick
|
9
|
+
attribute :source, key: "src"
|
10
|
+
attribute :input, key: "in"
|
9
11
|
|
10
12
|
def initialize(tick:, source:)
|
11
13
|
@tick = tick
|
12
|
-
@source =
|
14
|
+
@source = source
|
15
|
+
@input = @tick.send(source)
|
16
|
+
initialize_data_points
|
13
17
|
end
|
14
18
|
|
15
|
-
def
|
16
|
-
|
17
|
-
end
|
18
|
-
|
19
|
-
def timestamp
|
20
|
-
@tick.close_timestamp
|
21
|
-
end
|
22
|
-
|
23
|
-
def initialize_data_points(indicator:)
|
24
|
-
# NoOp
|
25
|
-
end
|
26
|
-
|
27
|
-
def to_h
|
28
|
-
raise NotImplementedError
|
29
|
-
end
|
30
|
-
|
31
|
-
def to_json(*args)
|
32
|
-
Oj.dump(to_h, *args)
|
19
|
+
def initialize_data_points
|
20
|
+
# No-Op - Override in subclass if needed.
|
33
21
|
end
|
34
22
|
end
|
35
23
|
end
|
data/lib/quant/indicators/ma.rb
CHANGED
@@ -1,46 +1,38 @@
|
|
1
1
|
module Quant
|
2
2
|
class Indicators
|
3
3
|
class MaPoint < IndicatorPoint
|
4
|
+
attribute :ss, key: "ss"
|
5
|
+
attribute :ema, key: "ema"
|
4
6
|
attr_accessor :ss, :ema, :osc
|
5
7
|
|
6
|
-
def
|
7
|
-
|
8
|
-
|
9
|
-
"ema" => delta_phase,
|
10
|
-
"osc" => osc
|
11
|
-
}
|
12
|
-
end
|
13
|
-
|
14
|
-
def initialize_data_points(indicator:)
|
15
|
-
@ss = oc2
|
16
|
-
@ema = oc2
|
8
|
+
def initialize_data_points
|
9
|
+
@ss = input
|
10
|
+
@ema = input
|
17
11
|
@osc = nil
|
18
12
|
end
|
19
13
|
end
|
20
14
|
|
21
15
|
# Moving Averages
|
22
16
|
class Ma < Indicator
|
23
|
-
|
24
|
-
"ma"
|
25
|
-
end
|
17
|
+
include Quant::Mixins::Filters
|
26
18
|
|
27
19
|
def alpha(period)
|
28
20
|
bars_to_alpha(period)
|
29
21
|
end
|
30
22
|
|
31
23
|
def min_period
|
32
|
-
|
24
|
+
8 # Quant.config.indicators.min_period
|
33
25
|
end
|
34
26
|
|
35
|
-
def
|
36
|
-
|
27
|
+
def max_period
|
28
|
+
48 # Quant.config.indicators.max_period
|
37
29
|
end
|
38
30
|
|
39
31
|
def compute
|
40
|
-
p0.ss = super_smoother
|
41
|
-
p0.ema = alpha(
|
32
|
+
# p0.ss = super_smoother input, :ss, min_period
|
33
|
+
p0.ema = alpha(max_period) * input + (1 - alpha(max_period)) * p1.ema
|
42
34
|
p0.osc = p0.ss - p0.ema
|
43
35
|
end
|
44
36
|
end
|
45
37
|
end
|
46
|
-
end
|
38
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Quant
|
2
|
+
class Indicators
|
3
|
+
class PingPoint < IndicatorPoint
|
4
|
+
attribute :pong
|
5
|
+
attribute :compute_count, default: 0
|
6
|
+
end
|
7
|
+
|
8
|
+
# A simple idicator used primarily to test the indicator system
|
9
|
+
class Ping < Indicator
|
10
|
+
def compute
|
11
|
+
p0.pong = input
|
12
|
+
p0.compute_count += 1
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/quant/indicators.rb
CHANGED
@@ -1,29 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Quant
|
4
|
-
#
|
4
|
+
# TODO: build an Indicator registry so new indicators can be added and used outside those shipped with the library.
|
5
5
|
class Indicators
|
6
|
-
# def atr; indicator(Indicators::Atr) end
|
7
|
-
# def adx; indicator(Indicators::Adx) end
|
8
|
-
# def cci; indicator(Indicators::Cci) end
|
9
|
-
# def cdi; indicator(Indicators::Cdi) end
|
10
|
-
# def decycler; indicator(Indicators::Decycler) end
|
11
|
-
# def frema; indicator(Indicators::Frema) end
|
12
|
-
# def hilo; indicator(Indicators::HiLo) end
|
13
|
-
# def ma; indicator(Indicators::Ma) end
|
14
|
-
# def mama; indicator(Indicators::Mama) end
|
15
|
-
# def frama; indicator(Indicators::Frama) end
|
16
|
-
# def mesa; indicator(Indicators::Mesa) end
|
17
|
-
# def roofing; indicator(Indicators::Roofing) end
|
18
|
-
# def rsi; indicator(Indicators::Rsi) end
|
19
|
-
# def rrr; indicator(Indicators::Rrr) end
|
20
|
-
# def rrsi; indicator(Indicators::RocketRsi) end
|
21
|
-
# def samo; indicator(Indicators::Samo) end
|
22
|
-
# def snr; indicator(Indicators::Snr) end
|
23
|
-
# def ssf; indicator(Indicators::Ssf) end
|
24
|
-
# def volume; indicator(Indicators::VolumeSsf) end
|
25
|
-
# def vol; indicator(Indicators::Vol) end
|
26
|
-
# def vrsi; indicator(Indicators::VolumeRsi) end
|
27
|
-
# def weibull; indicator(Indicators::Weibull) end
|
28
6
|
end
|
29
7
|
end
|