quantitative 0.1.3 → 0.1.4

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: 5bfe61d98618c7cfb83052426689976be38c45e83fce9217a74a4f0392897b60
4
- data.tar.gz: 061d9a0179eb913c5f5f5d9f1016998c2cbc0d65da9a774620a3b591f18a1f49
3
+ metadata.gz: 266a7aa51d29b809224fa76091d26c52d58f6e42959aeeb4ca5ffb6376828773
4
+ data.tar.gz: 5b3ac92706338a77a098e5dee72f3ecf57f2c4032f946533225e6061d07082d5
5
5
  SHA512:
6
- metadata.gz: 4154a9e589bcffd15b3415ace9c1ccc6b8d29ba5ecc0180e48259c649a746a157f58bd89aeabad4ffc4ac5edefe6f1892c94adcd001ba5d1f039a5bb46a8a9d0
7
- data.tar.gz: 7ac2b4661e6c4b0e02fda9389f73b8d007b92e754e8b4fa821bb55dca1d085dfd7e2e3eb6608d520a2e2e6008eb837aa75e7c07c05addc28af577b92fe98f8c3
6
+ metadata.gz: 624d6945e690d51b5afef5ebc7939eb3f444fd7d4d79a31e73df5a42e0f6c351f8d4ac451a455a657c96a07448a0c724ba1481156d2e859ca720c8994328547a
7
+ data.tar.gz: 51b9fd16424fe1fd1b48c72f350c89cfb9e26e0a082eb750ae864c436b51eeab2142c64744deee93b91aaafe119354f19a4159ecda84b066d75f1d242945a9a2
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- quantitative (0.1.3)
4
+ quantitative (0.1.4)
5
5
  oj (~> 3.10)
6
6
 
7
7
  GEM
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Quant
4
+ module Config
5
+ class Config
6
+ attr_reader :indicators
7
+
8
+ def initialize
9
+ @indicators = Settings::Indicators.defaults
10
+ end
11
+
12
+ def apply_indicator_settings(**settings)
13
+ @indicators.apply_settings(**settings)
14
+ end
15
+ end
16
+
17
+ def self.config
18
+ @config ||= Config.new
19
+ end
20
+ end
21
+
22
+ module_function
23
+
24
+ def config
25
+ Config.config
26
+ end
27
+
28
+ def configure_indicators(**settings)
29
+ config.apply_indicator_settings(**settings)
30
+ yield config.indicators if block_given?
31
+ end
32
+ end
@@ -0,0 +1,136 @@
1
+ module Quant
2
+ class Indicators
3
+ class Indicator
4
+ # include Enumerable
5
+
6
+ # # include Mixins::TrendMethods
7
+ # include Mixins::Trig
8
+ # include Mixins::WeightedAverage
9
+ # include Mixins::HilbertTransform
10
+ # include Mixins::SuperSmoother
11
+ # include Mixins::Stochastic
12
+ # include Mixins::FisherTransform
13
+ # include Mixins::HighPassFilter
14
+ # include Mixins::Direction
15
+ # include Mixins::Filters
16
+
17
+ # def inspect
18
+ # "#<#{self.class.name} #{symbol} #{interval} #{points.size} points>"
19
+ # end
20
+
21
+ # def compute
22
+ # raise NotImplementedError
23
+ # end
24
+
25
+ # def [](index)
26
+ # points[index]
27
+ # end
28
+
29
+ # def after_append
30
+ # # NoOp
31
+ # end
32
+
33
+ # def points_class
34
+ # "Quant::Indicators::#{indicator_name}Point".constantize
35
+ # end
36
+
37
+ # def indicator_name
38
+ # self.class.name.demodulize
39
+ # end
40
+
41
+ # def warmed_up?
42
+ # true
43
+ # end
44
+
45
+ # def initial_max_size
46
+ # value = [series.size, series.max_size].max
47
+ # value.zero? ? settings.initial_max_size : value
48
+ # end
49
+
50
+ attr_reader :series #, :settings, :max_size, :points, :dc_period
51
+ # delegate :p0, :p1, :p2, :p3, :prev, :iteration, to: :points
52
+ # delegate :each, :size, :[], :last, :first, to: :points
53
+ # delegate :oc2, :high_price, :low_price, :open_price, :close_price, :volume, to: :p0
54
+
55
+ def initialize(series:) # settings: Settings::Indicators.defaults, cloning: false)
56
+ @series = series
57
+ # @settings = settings
58
+ # @max_size = initial_max_size
59
+ # @points = Points.new(indicator: self)
60
+ # return if cloning
61
+
62
+ # after_initialization
63
+ # parent_series.each { |ohlc| append ohlc }
64
+ # @points_for_cache = {}
65
+ # @dc_period = nil
66
+ end
67
+
68
+ # def points_for(series:)
69
+ # @points_for_cache[series] ||= self.class.new(series:, settings:, cloning: true).tap do |indicator|
70
+ # series.ticks.each { |tick| indicator.points.push(tick.indicators[self]) }
71
+ # end
72
+ # end
73
+
74
+ # # Ticks belong to the first series they're associated with always
75
+ # # NOTE: No provisions for series merging their ticks to one series!
76
+ # def parent_series
77
+ # series.ticks.empty? ? series : series.ticks.first.series
78
+ # end
79
+
80
+ # def after_initialization
81
+ # # NoOp
82
+ # end
83
+
84
+ # # Returns the last point of the current indicator rather than the entire series
85
+ # # This is used for indicators that depend on dominant cycle or other indicators
86
+ # # to compute their data points.
87
+ # def current_point
88
+ # points.size - 1
89
+ # end
90
+
91
+ # def dominant_cycles
92
+ # parent_series.indicators.dominant_cycles
93
+ # end
94
+
95
+ # # Override this method to change source of dominant cycle computation for an indicator
96
+ # def dominant_cycle_indicator
97
+ # @dominant_cycle_indicator ||= dominant_cycles.band_pass
98
+ # end
99
+
100
+ # def ensure_not_dominant_cycler_indicator
101
+ # return unless is_a? Quant::Indicators::DominantCycles::DominantCycle
102
+
103
+ # raise 'Dominant Cycle Indicators cannot use the thing they compute!'
104
+ # end
105
+
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
+ # # Returns the dominant cycle point for the current indicator's point
114
+ # def current_dominant_cycle
115
+ # dominant_cycle_indicator[current_point]
116
+ # end
117
+
118
+ # # Returns the atr point for the current indicator's point
119
+ # def atr_point
120
+ # parent_series.indicators.atr[current_point]
121
+ # end
122
+
123
+ # # def dc_period
124
+ # # dominant_cycle.period.round(0).to_i
125
+ # # end
126
+
127
+ # def <<(ohlc)
128
+ # points.append(ohlc)
129
+ # end
130
+
131
+ # def append(ohlc)
132
+ # points.append(ohlc)
133
+ # end
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Quant
4
+ class Indicators
5
+ class IndicatorPoint
6
+ extend Forwardable
7
+
8
+ attr_reader :tick, :source
9
+
10
+ def initialize(tick:, source:)
11
+ @tick = tick
12
+ @source = @tick.send(source)
13
+ end
14
+
15
+ def volume
16
+ @tick.base_volume
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)
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,46 @@
1
+ module Quant
2
+ class Indicators
3
+ class MaPoint < IndicatorPoint
4
+ attr_accessor :ss, :ema, :osc
5
+
6
+ def to_h
7
+ {
8
+ "ss" => ss,
9
+ "ema" => delta_phase,
10
+ "osc" => osc
11
+ }
12
+ end
13
+
14
+ def initialize_data_points(indicator:)
15
+ @ss = oc2
16
+ @ema = oc2
17
+ @osc = nil
18
+ end
19
+ end
20
+
21
+ # Moving Averages
22
+ class Ma < Indicator
23
+ def self.indicator_key
24
+ "ma"
25
+ end
26
+
27
+ def alpha(period)
28
+ bars_to_alpha(period)
29
+ end
30
+
31
+ def min_period
32
+ settings.min_period
33
+ end
34
+
35
+ def period
36
+ settings.max_period
37
+ end
38
+
39
+ def compute
40
+ p0.ss = super_smoother p0.oc2, :ss, min_period
41
+ p0.ema = alpha(period) * p0.oc2 + (1 - alpha(period)) * p1.ema
42
+ p0.osc = p0.ss - p0.ema
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Quant
4
+ # < IndicatorsAccessor
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
+ end
29
+ end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Quant
4
+ module Settings
5
+ # Indicator settings provide a way to configure the default settings for indicators.
6
+ # Many of the indicators are built in adaptive measuring of the dominant cycle and these settings
7
+ # provide a way to configure your choices for the indicators. The default values come from various
8
+ # papers and books on the subject of technical analysis by John Ehlers where he variously suggests
9
+ # a minimum period of 8 or 10 and a max period of 48.
10
+ #
11
+ # The half period is the average of the max_period and min_period.
12
+ # The micro period comes from Ehler's writings on Swami charts and auto-correlation computations, which
13
+ # is a period of 3 bars. It is useful enough in various indicators to be its own setting.
14
+ #
15
+ # The dominant cycle kind is the kind of dominant cycle to use in the indicator. The default is +:settings+
16
+ # which means the dominant cycle is whatever the +max_period+ is set to. It is not adaptive when configured
17
+ # this way. The other kinds are adaptive and are computed from the series data. The choices are:
18
+ # * +:settings+ - the max_period is the dominant cycle and is not adaptive
19
+ # * +:band_pass+ - The zero crossings of the band pass filter are used to compute the dominant cycle
20
+ # * +:auto_correlation_reversal+ - The dominant cycle is computed from the auto-correlation of the series.
21
+ # * +:homodyne+ - The dominant cycle is computed from the homodyne discriminator.
22
+ # * +:differential+ - The dominant cycle is computed from the differential discriminator.
23
+ # * +:phase_accumulator+ - The dominant cycle is computed from the phase accumulator.
24
+ #
25
+ # All of the above are adaptive and are computed from the series data and are described in John Ehlers' books
26
+ # and published papers.
27
+ #
28
+ # Pivot kinds are started as the classic pivot points and then expanded to include other kinds of bands that
29
+ # follow along with price action such as Donchian channels, Fibonacci bands, Bollinger bands, Keltner bands,
30
+ # etc. The choices are as follows:
31
+ # * +:pivot+ - Classic pivot points
32
+ # * +:donchian+ - Donchian channels
33
+ # * +:fibbonacci+ - Fibonacci bands
34
+ # * +:woodie+ - Woodie's pivot points
35
+ # * +:classic+ - Classic pivot points
36
+ # * +:camarilla+ - Camarilla pivot points
37
+ # * +:demark+ - Demark pivot points
38
+ # * +:murrey+ - Murrey math pivot points
39
+ # * +:keltner+ - Keltner bands
40
+ # * +:bollinger+ - Bollinger bands
41
+ # * +:guppy+ - Guppy bands
42
+ # * +:atr+ - ATR bands
43
+ #
44
+ class Indicators
45
+ # Returns an instance of the settings for indicators configured with defaults derived from
46
+ # defined constants in the +Quant::Settings+ module.
47
+ def self.defaults
48
+ new
49
+ end
50
+
51
+ attr_accessor :max_period, :min_period, :half_period, :micro_period
52
+ attr_accessor :dominant_cycle_kind, :pivot_kind
53
+
54
+ def initialize(**settings)
55
+ @max_period = settings[:max_period] || Settings::MAX_PERIOD
56
+ @min_period = settings[:min_period] || Settings::MIN_PERIOD
57
+ @half_period = settings[:half_period] || compute_half_period
58
+ @micro_period = settings[:micro_period] || Settings::MICRO_PERIOD
59
+
60
+ @dominant_cycle_kind = settings[:dominant_cycle_kind] || Settings::DOMINANT_CYCLE_KINDS.first
61
+ @pivot_kind = settings[:pivot_kind] || Settings::PIVOT_KINDS.first
62
+ end
63
+
64
+ def apply_settings(**settings)
65
+ @max_period = settings.fetch(:max_period, @max_period)
66
+ @min_period = settings.fetch(:min_period, @min_period)
67
+ @half_period = settings.fetch(:half_period, @half_period || compute_half_period)
68
+ @micro_period = settings.fetch(:micro_period, @micro_period)
69
+ @dominant_cycle_kind = settings.fetch(:dominant_cycle_kind, @dominant_cycle_kind)
70
+ @pivot_kind = settings.fetch(:pivot_kind, @pivot_kind)
71
+ end
72
+
73
+ def compute_half_period
74
+ (max_period + min_period) / 2
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,48 @@
1
+ module Quant
2
+ module Settings
3
+ MAX_PERIOD = 48
4
+ MIN_PERIOD = 10
5
+ HALF_PERIOD = (MAX_PERIOD + MIN_PERIOD) / 2
6
+ MICRO_PERIOD = 3
7
+
8
+ PIVOT_KINDS = %i(
9
+ pivot
10
+ donchian
11
+ fibbonacci
12
+ woodie
13
+ classic
14
+ camarilla
15
+ demark
16
+ murrey
17
+ keltner
18
+ bollinger
19
+ guppy
20
+ atr
21
+ ).freeze
22
+
23
+ DOMINANT_CYCLE_KINDS = %i(
24
+ settings
25
+ band_pass
26
+ auto_correlation_reversal
27
+ homodyne
28
+ differential
29
+ phase_accumulator
30
+ ).freeze
31
+
32
+ # ---- Risk Management Ratio Settings ----
33
+ # Risk Reward Breakeven Win Rate %
34
+ # 50 1 98%
35
+ # 10 1 91%
36
+ # 5 1 83%
37
+ # 3 1 75%
38
+ # 2 1 67%
39
+ # 1 1 50%
40
+ # 1 2 33%
41
+ # 1 3 25%
42
+ # 1 5 17%
43
+ # 1 10 9%
44
+ # 1 50 2%
45
+ PROFIT_TARGET_PCT = 0.03
46
+ STOP_LOSS_PCT = 0.01
47
+ end
48
+ end
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.3"
4
+ VERSION = "0.1.4"
5
5
  end
data/lib/quantitative.rb CHANGED
@@ -12,6 +12,6 @@ quant_folder = File.join(lib_folder, "quant")
12
12
  Dir.glob(File.join(quant_folder, "*.rb")).each { |fn| require fn }
13
13
 
14
14
  # require sub-folders and their sub-folders
15
- %w(refinements ticks).each do |sub_folder|
15
+ %w(refinements settings ticks indicators).each do |sub_folder|
16
16
  Dir.glob(File.join(quant_folder, sub_folder, "**/*.rb")).each { |fn| require fn }
17
- end
17
+ 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.3
4
+ version: 0.1.4
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-15 00:00:00.000000000 Z
11
+ date: 2024-02-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: oj
@@ -44,7 +44,12 @@ files:
44
44
  - LICENSE
45
45
  - README.md
46
46
  - Rakefile
47
+ - lib/quant/config.rb
47
48
  - lib/quant/errors.rb
49
+ - lib/quant/indicators.rb
50
+ - lib/quant/indicators/indicator.rb
51
+ - lib/quant/indicators/indicator_point.rb
52
+ - lib/quant/indicators/ma.rb
48
53
  - lib/quant/interval.rb
49
54
  - lib/quant/mixins/direction.rb
50
55
  - lib/quant/mixins/filters.rb
@@ -59,6 +64,8 @@ files:
59
64
  - lib/quant/security.rb
60
65
  - lib/quant/security_class.rb
61
66
  - lib/quant/series.rb
67
+ - lib/quant/settings.rb
68
+ - lib/quant/settings/indicators.rb
62
69
  - lib/quant/ticks/ohlc.rb
63
70
  - lib/quant/ticks/serializers/ohlc.rb
64
71
  - lib/quant/ticks/serializers/spot.rb