quantitative 0.5.0 → 0.6.0

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: 8d68c387b70e811a933f804ccc410a9a7eb5382b40c01f806cd446d8d3f893ec
4
- data.tar.gz: 4d19edc74c74e80ff5cd14bfe0906efad8ee7518ef15e17e7365faf9067b83cf
3
+ metadata.gz: 3f00aee096aa1bbed04ac495bfca0d468eccee92e84ca1cc5d0e7c868299489d
4
+ data.tar.gz: 2d06fc2b90c09ceb39e471360917895c99c64501b4c577e5a288fcea8134f658
5
5
  SHA512:
6
- metadata.gz: '08c361a6745b972d50d47b6f73a4e455ae56e5a8a770b1c62ef2ca21e2893c4831e655be702c25c02f0af2edffb561b6db75a7ecc15b080c780442f0eeede8a7'
7
- data.tar.gz: e29e29bd0bdaf461bbb9581dda8aac99c8dab99c947e31a133710aa62c2ee4a7aa078297cf2f1868a795d7384a834e3dd4a69d124f4017cdf8854b936349415f
6
+ metadata.gz: 62eea4fce9e5588ccd9dd4ba25bcc1369b82b3c79821394a5c2583a0a47216fa7cb06a45e533568b4e8cd69b57a69c72211dfbeb24c3cccbf6faf30739da8e97
7
+ data.tar.gz: 61da1a83ea015eb49b55c99ea6d539293756af1e2ac927006891e9167c2de046295d00204af29aa55300945600c80a2e65dae3d968667d598177bc33629989ef
data/CHANGELOG.md CHANGED
@@ -7,6 +7,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ---
9
9
 
10
+ ## [0.6.0] — 2026-06-13
11
+
12
+ ### Added
13
+
14
+ - **`Quant::Indicators::DominantCycles::SuppliedPeriod`** — generalization of the prior `HalfPeriod` slot. The class doc names four canonical supply modes (fixed / manual / configured / external) that consumers compose freely. The `compute` method stays no-op; whoever sets `point.period` controls the period that downstream indicators reading `adaptive_period` see. The substrate-driven external mode is the load-bearing pattern for tick-derived adaptive lookbacks (e.g., Fishy peak-count cycle period) where another process writes the period to a runtime store and the integration site reads + populates the point.
15
+ - **`:supplied_period`** symbol registered alongside the other DC kinds; it is the new default for `Settings::Indicators#dominant_cycle_kind`.
16
+
17
+ ### Deprecated (removed in 0.9.0)
18
+
19
+ - **`Quant::Indicators::DominantCycles::HalfPeriod`** → use `SuppliedPeriod`. The old constant remains as an alias and is marked via `Module#deprecate_constant`; each access emits a Ruby deprecation warning. The two are equivalent at runtime; the rename clarifies the underlying capability.
20
+ - **`Quant::Indicators::DominantCycles::HalfPeriodPoint`** → use `SuppliedPeriodPoint`. Same alias + `deprecate_constant` treatment.
21
+ - **`:half_period` dominant_cycle_kind symbol** → use `:supplied_period`. `Settings::Indicators#dominant_cycle_indicator_class` resolves the deprecated symbol to `SuppliedPeriod` and emits a one-time-per-instance warning via `warn`.
22
+
23
+ The unrelated `Settings::Indicators#half_period` method (returns `(max_period + min_period) / 2`) and the point default symbol `:half_period` (which references that method, not the deprecated class) are NOT deprecated and continue to work unchanged.
24
+
25
+ See `Quant::Indicators::DominantCycles::SuppliedPeriod` class doc §Migration for the upgrade path. Existing consumers see identical runtime behavior; only the names change.
26
+
27
+ ---
28
+
10
29
  ## [0.5.0] — 2026-05-22
11
30
 
12
31
  ### Changed (breaking)
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- quantitative (0.5.0)
4
+ quantitative (0.6.0)
5
5
  csv
6
6
  oj (~> 3.10)
7
7
  zeitwerk (~> 2.6)
@@ -6,8 +6,9 @@ module Quant
6
6
  #
7
7
  # Quant.configure_indicators(min_period: 8, max_period: 32)
8
8
  #
9
- # The default dominant cycle kind is the `half_period` filter. This can be adjusted by setting
10
- # the `dominant_cycle_kind` configuration value in {Quant::Config}.
9
+ # The default dominant cycle kind is the `supplied_period` slot (formerly `half_period`; the old name
10
+ # is deprecated since 0.6.0 and removed in 0.9.0). This can be adjusted by setting the
11
+ # `dominant_cycle_kind` configuration value in {Quant::Config}.
11
12
  #
12
13
  # Quant.configure_indicators(dominant_cycle_kind: :band_pass)
13
14
  #
@@ -0,0 +1,171 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Quant
4
+ module Indicators
5
+ module DominantCycles
6
+ # `SuppliedPeriod` — a dominant-cycle slot whose period is supplied
7
+ # by the caller rather than computed from price data. The `compute`
8
+ # method is intentionally a no-op; whatever sets `point.period` is
9
+ # the period that downstream indicators reading `adaptive_period`
10
+ # will see.
11
+ #
12
+ # Use this when you want a downstream indicator's lookback window
13
+ # to come from somewhere other than the indicator's own cycle
14
+ # detection — a fixed constant, an operator setting, a config
15
+ # value, or a separate runtime process. Four canonical modes,
16
+ # distinguished only by *who* sets the period and *when*:
17
+ #
18
+ # | Mode | Period source | When set | Example use case |
19
+ # |------------|----------------------------------------|------------------|-------------------------------------------|
20
+ # | Fixed | Literal value at construction | Once | RSI(14), SMA(20) — classical lookbacks |
21
+ # | Manual | Operator-mutable runtime setting | On every read | Settings page, Pool config tuning |
22
+ # | Configured | `Quant.config.indicators` symbol | On every read | Project-wide default lookback |
23
+ # | External | Substrate written by another process | Per-tick by collector | Tick-derived adaptive period (Fishy peak-count) |
24
+ #
25
+ # ## Mode 1: Fixed
26
+ #
27
+ # Period is a literal value, set once at construction, never
28
+ # changes. The classical "RSI(14)" / "SMA(20)" shape.
29
+ #
30
+ # Quant.config.indicators.dominant_cycle_kind = :supplied_period
31
+ # indicator = MyIndicator.new(series: series)
32
+ # indicator.dominant_cycle.p0.period = 14 # fixed lookback
33
+ #
34
+ # ## Mode 2: Manual (operator-tunable at runtime)
35
+ #
36
+ # Period is set from a value the operator changes via UI, config
37
+ # file reload, settings page, etc. The slot reads whatever value
38
+ # is current when the indicator runs.
39
+ #
40
+ # point.period = pool.config.fetch(:lookback_window)
41
+ #
42
+ # When the operator updates `pool.config[:lookback_window]`, the
43
+ # next tick sees the new value. No re-instantiation needed.
44
+ #
45
+ # ## Mode 3: Configured (Quant.config-resolved default)
46
+ #
47
+ # Period defaults to a symbol (`:half_period`) that resolves
48
+ # through `Quant.config.indicators` at indicator construction
49
+ # time. This was the original `HalfPeriod` usage — the parent
50
+ # `Indicator#half_period` resolves to
51
+ # `(min_period + max_period) / 2` from the active config.
52
+ #
53
+ # The default symbol mechanism resolves once per indicator
54
+ # instance; if the operator mutates `Quant.config.indicators`
55
+ # after construction, existing indicator instances continue
56
+ # using the resolved-at-construction value. Construct a fresh
57
+ # indicator to pick up the new config (or use Mode 2 / 4 if
58
+ # you need true runtime tracking).
59
+ #
60
+ # class SuppliedPeriodPoint < IndicatorPoint
61
+ # attribute :period, default: :half_period
62
+ # end
63
+ #
64
+ # # consumer site — no explicit set; default symbol resolves:
65
+ # indicator.dominant_cycle.p0.period # => 18 (resolved from config)
66
+ #
67
+ # ## Mode 4: External (runtime-supplied by a separate process)
68
+ #
69
+ # Period is supplied per-tick by a separate producer writing to
70
+ # substrate. The integration site (collector, service, anywhere
71
+ # downstream of the producer) reads the substrate and sets
72
+ # `point.period` before consumers read `adaptive_period`.
73
+ #
74
+ # Example pattern: a producer computes a tick-stream peak-to-peak
75
+ # period and writes it to substrate. A consuming indicator's
76
+ # collector instance reads the substrate value and populates the
77
+ # supplied-period slot:
78
+ #
79
+ # period_seconds = substrate.read(platform, listing).period_seconds
80
+ # period_bars = period_seconds / series.interval.to_seconds
81
+ # indicator.dominant_cycle.p0.period = period_bars
82
+ #
83
+ # The substrate-driven external mode is the load-bearing pattern
84
+ # for tick-derived adaptive lookbacks — but the slot itself is
85
+ # mode-agnostic; consumers compose any of the four modes per
86
+ # their need.
87
+ #
88
+ # ## Why no-op `compute`?
89
+ #
90
+ # The `DominantCycle` framework's contract is that
91
+ # `Indicator#dominant_cycle_indicator_class.compute` runs once per
92
+ # tick, then consumers read `point.period`. `SuppliedPeriod`
93
+ # short-circuits that — `compute` runs (no-op), and `point.period`
94
+ # carries whatever the caller put there. This lets the polymorphic
95
+ # DC dispatch (`Indicator#dominant_cycle`) treat externally-driven
96
+ # period sources identically to algorithmically-computed ones.
97
+ #
98
+ # ## Default fallback
99
+ #
100
+ # When no caller sets `point.period`, the attribute default
101
+ # (`:half_period`) provides safe behavior: downstream indicators
102
+ # see the midpoint-of-min-max-period config value, which is what
103
+ # they got pre-rename with `HalfPeriod`. Backward-compatible.
104
+ #
105
+ # Note: the default symbol `:half_period` refers to the
106
+ # `Settings::Indicators#half_period` method (the `(max+min)/2`
107
+ # attribute), NOT the deprecated `HalfPeriod` class. The method
108
+ # is not deprecated and is unaffected by this rename.
109
+ #
110
+ # ## Migration from HalfPeriod (deprecated; removed in 0.9.0)
111
+ #
112
+ # Prior to 0.6.0 this class was named `HalfPeriod`. The old name
113
+ # was descriptive of one resolved value (the midpoint of min/max
114
+ # period in config) rather than the underlying capability (a slot
115
+ # whose period is supplied externally). The rename clarifies that
116
+ # the slot supports four equivalent modes — see table above.
117
+ #
118
+ # The old names continue to work through 0.8.x but emit Ruby
119
+ # deprecation warnings via `Module#deprecate_constant`:
120
+ #
121
+ # HalfPeriod = SuppliedPeriod # deprecated; warns at access
122
+ # HalfPeriodPoint = SuppliedPeriodPoint # deprecated; warns at access
123
+ #
124
+ # The registry symbol `:half_period` continues to resolve to
125
+ # `SuppliedPeriod` for `Quant.config.indicators.dominant_cycle_kind`
126
+ # through 0.8.x; the resolver emits a one-time deprecation warning
127
+ # per `Quant::Settings::Indicators` instance when `:half_period`
128
+ # is the lookup key.
129
+ #
130
+ # **To migrate** (any 0.6.x or later):
131
+ #
132
+ # # before:
133
+ # Quant.config.indicators.dominant_cycle_kind = :half_period
134
+ # point = Quant::Indicators::DominantCycles::HalfPeriodPoint.new(...)
135
+ #
136
+ # # after:
137
+ # Quant.config.indicators.dominant_cycle_kind = :supplied_period
138
+ # point = Quant::Indicators::DominantCycles::SuppliedPeriodPoint.new(...)
139
+ #
140
+ # The point's `period` attribute default stays `:half_period` —
141
+ # that's the resolved-via-config symbol (Mode 3) and a sensible
142
+ # safe default; it is NOT the deprecated class name and is not
143
+ # affected by the rename. Existing consumers see identical
144
+ # runtime behavior.
145
+ #
146
+ # **Removal**: `HalfPeriod` / `HalfPeriodPoint` constants and the
147
+ # `:half_period` registry alias are scheduled for removal in
148
+ # quantitative 0.9.0. Migrate any time before then.
149
+ class SuppliedPeriodPoint < Quant::Indicators::IndicatorPoint
150
+ attribute :period, default: :half_period
151
+ end
152
+
153
+ class SuppliedPeriod < DominantCycle
154
+ register name: :supplied_period
155
+
156
+ def compute
157
+ # No-Op — `period` is supplied by the caller (see class doc
158
+ # for the four canonical supply modes).
159
+ end
160
+ end
161
+
162
+ # Deprecated aliases — removed in 0.9.0. See `SuppliedPeriod`
163
+ # class doc §Migration for the upgrade path.
164
+ HalfPeriodPoint = SuppliedPeriodPoint
165
+ HalfPeriod = SuppliedPeriod
166
+
167
+ deprecate_constant :HalfPeriod
168
+ deprecate_constant :HalfPeriodPoint
169
+ end
170
+ end
171
+ end
@@ -14,15 +14,19 @@ module Quant
14
14
  # The micro period comes from Ehler's writings on Swami charts and auto-correlation computations, which
15
15
  # is a period of 3 bars. It is useful enough in various indicators to be its own setting.
16
16
  #
17
- # The dominant cycle kind is the kind of dominant cycle to use in the indicator. The default is +:settings+
18
- # which means the dominant cycle is whatever the +max_period+ is set to. It is not adaptive when configured
19
- # this way. The other kinds are adaptive and are computed from the series data. The choices are:
20
- # * +:half_period+ - the half_period is the dominant cycle and is not adaptive
17
+ # The dominant cycle kind is the kind of dominant cycle to use in the indicator. The default is +:supplied_period+
18
+ # which means the period is supplied by the caller (defaulting to the half_period config value). It is not
19
+ # adaptive when configured this way. The other kinds are adaptive and are computed from the series data.
20
+ # The choices are:
21
+ # * +:supplied_period+ - The period is supplied externally by the caller; not adaptive (see SuppliedPeriod doc
22
+ # for the four canonical supply modes: fixed, manual, configured, external). Default.
21
23
  # * +:band_pass+ - The zero crossings of the band pass filter are used to compute the dominant cycle
22
24
  # * +:auto_correlation_reversal+ - The dominant cycle is computed from the auto-correlation of the series.
23
25
  # * +:homodyne+ - The dominant cycle is computed from the homodyne discriminator.
24
26
  # * +:differential+ - The dominant cycle is computed from the differential discriminator.
25
27
  # * +:phase_accumulator+ - The dominant cycle is computed from the phase accumulator.
28
+ # * +:half_period+ - **Deprecated** alias for +:supplied_period+; removed in 0.9.0. Resolver emits a
29
+ # one-time warning per Settings::Indicators instance when this symbol is used.
26
30
  #
27
31
  # All of the above are adaptive and are computed from the series data and are described in John Ehlers' books
28
32
  # and published papers.
@@ -89,7 +93,17 @@ module Quant
89
93
  def dominant_cycle_indicator_class
90
94
  return @dominant_cycle_indicator_class if @dominant_cycle_indicator_class
91
95
 
92
- base_class_name = dominant_cycle_kind.to_s.split("_").map(&:capitalize).join
96
+ resolved_kind = Settings::DEPRECATED_DOMINANT_CYCLE_KIND_ALIASES[dominant_cycle_kind] || dominant_cycle_kind
97
+ if resolved_kind != dominant_cycle_kind
98
+ @dc_kind_deprecation_warned ||= begin
99
+ warn "[DEPRECATION] dominant_cycle_kind: :#{dominant_cycle_kind} is renamed to " \
100
+ ":#{resolved_kind} (scheduled for removal in quantitative 0.9.0). " \
101
+ "See Quant::Indicators::DominantCycles::SuppliedPeriod doc §Migration."
102
+ true
103
+ end
104
+ end
105
+
106
+ base_class_name = resolved_kind.to_s.split("_").map(&:capitalize).join
93
107
  class_name = "Quant::Indicators::DominantCycles::#{base_class_name}"
94
108
 
95
109
  @dominant_cycle_indicator_class = Object.const_get(class_name)
@@ -23,14 +23,23 @@ module Quant
23
23
  ).freeze
24
24
 
25
25
  DOMINANT_CYCLE_KINDS = %i(
26
- half_period
26
+ supplied_period
27
27
  band_pass
28
28
  auto_correlation_reversal
29
29
  homodyne
30
30
  differential
31
31
  phase_accumulator
32
+ half_period
32
33
  ).freeze
33
34
 
35
+ # Deprecated `dominant_cycle_kind` symbols that resolve to current
36
+ # symbols via `Settings::Indicators#dominant_cycle_indicator_class`.
37
+ # Each access emits a one-time-per-instance deprecation warning.
38
+ # Removed in 0.9.0.
39
+ DEPRECATED_DOMINANT_CYCLE_KIND_ALIASES = {
40
+ half_period: :supplied_period
41
+ }.freeze
42
+
34
43
  # ---- Risk Management Ratio Settings ----
35
44
  # Risk Reward Breakeven Win Rate %
36
45
  # 50 1 98%
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.5.0"
4
+ VERSION = "0.6.0"
5
5
  end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/quant/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "quantitative"
7
+ spec.version = Quant::VERSION
8
+ spec.authors = ["Michael Lang"]
9
+ spec.email = ["mwlang@cybrains.net"]
10
+
11
+ spec.summary = "Quantitative and statistical tools written for Ruby for trading and finance."
12
+ spec.description = spec.summary
13
+ spec.homepage = "https://github.com/mwlang/quantitative"
14
+ spec.license = "MIT"
15
+ spec.required_ruby_version = ">= 3.3"
16
+
17
+ spec.metadata["allowed_push_host"] = "https://rubygems.org"
18
+
19
+ spec.metadata["homepage_uri"] = spec.homepage
20
+ spec.metadata["source_code_uri"] = spec.homepage
21
+ spec.metadata["changelog_uri"] = "#{spec.homepage}/blob/main/CHANGELOG.md"
22
+
23
+ # Specify which files should be added to the gem when it is released.
24
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
25
+ spec.files = Dir.chdir(__dir__) do
26
+ `git ls-files -z`.split("\x0").reject do |f|
27
+ (f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
28
+ end
29
+ end
30
+ spec.bindir = "exe"
31
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
32
+ spec.require_paths = ["lib"]
33
+
34
+ # Uncomment to register a new dependency of your gem
35
+ spec.add_dependency "csv"
36
+ spec.add_dependency "oj", "~> 3.10"
37
+ spec.add_dependency "zeitwerk", "~> 2.6"
38
+
39
+ # For more information and examples about making a new gem, check out our
40
+ # guide at: https://bundler.io/guides/creating_gem.html
41
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: quantitative
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Lang
@@ -87,9 +87,9 @@ files:
87
87
  - lib/quant/indicators/dominant_cycles/band_pass.rb
88
88
  - lib/quant/indicators/dominant_cycles/differential.rb
89
89
  - lib/quant/indicators/dominant_cycles/dominant_cycle.rb
90
- - lib/quant/indicators/dominant_cycles/half_period.rb
91
90
  - lib/quant/indicators/dominant_cycles/homodyne.rb
92
91
  - lib/quant/indicators/dominant_cycles/phase_accumulator.rb
92
+ - lib/quant/indicators/dominant_cycles/supplied_period.rb
93
93
  - lib/quant/indicators/ema.rb
94
94
  - lib/quant/indicators/frama.rb
95
95
  - lib/quant/indicators/indicator.rb
@@ -149,6 +149,7 @@ files:
149
149
  - lib/quant/version.rb
150
150
  - lib/quantitative.rb
151
151
  - possibilities.png
152
+ - quantitative.gemspec
152
153
  homepage: https://github.com/mwlang/quantitative
153
154
  licenses:
154
155
  - MIT
@@ -1,23 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Quant
4
- module Indicators
5
- module DominantCycles
6
- # This dominant cycle indicator is based on the half period
7
- # that is the midpoint of the `min_period` and `max_period`
8
- # configured in the `Quant.config.indicators` object.
9
- # Effectively providing a static, arbitrarily set period.
10
- class HalfPeriodPoint < Quant::Indicators::IndicatorPoint
11
- attribute :period, default: :half_period
12
- end
13
-
14
- class HalfPeriod < DominantCycle
15
- register name: :half_period
16
-
17
- def compute
18
- # No-Op
19
- end
20
- end
21
- end
22
- end
23
- end