quantitative 0.1.3 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
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