Skip to content

Trend: Schaff Trend Cycle (STC)#301

Merged
cinar merged 1 commit intomasterfrom
issue-53
Feb 22, 2026
Merged

Trend: Schaff Trend Cycle (STC)#301
cinar merged 1 commit intomasterfrom
issue-53

Conversation

@cinar
Copy link
Owner

@cinar cinar commented Feb 22, 2026

Describe Request

Trend: Schaff Trend Cycle (STC).

Fixed #53

Change Type

New indicator.

Summary by CodeRabbit

  • New Features

    • Added Slow Stochastic indicator for trend analysis
    • Added Schaff Trend Cycle (STC) indicator for trend analysis
  • Documentation

    • Updated trend indicators reference with new indicator definitions

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 22, 2026

πŸ“ Walkthrough

Walkthrough

This pull request adds two new technical indicators to the trend package: Slow Stochastic and Schaff Trend Cycle (STC). The changes include new generic type implementations, constructor and compute methods, an additional method on the existing Apo type, documentation updates, and corresponding tests.

Changes

Cohort / File(s) Summary
Documentation
README.md, trend/README.md
Added references to two new indicators (Slow Stochastic and Schaff Trend Cycle) in the Trend Indicators section with descriptive content in the trend package readme.
Apo Enhancement
trend/apo.go
Added public IdlePeriod() method to Apo[T] returning the initial non-yielding period; minor formatting adjustment in Compute function.
New Slow Stochastic Indicator
trend/slow_stochastic.go
Introduced new generic SlowStochastic[T] type with constructors NewSlowStochastic and NewSlowStochasticWithPeriod. Compute method calculates Fast %K using moving min/max, smooths to Slow %K and Slow %D via SMA, returning dual output channels. IdlePeriod returns Period + KPeriod + DPeriod - 3.
New Schaff Trend Cycle Indicator
trend/stc.go
Introduced new generic Stc[T] type composing Apo and Stochastic components. NewStc and NewStcWithPeriod constructors initialize with default or custom periods. Compute buffers inputs, applies MACD via Apo, chains Stochastic calculations, and yields scaled STC values. IdlePeriod combines component idle periods.
Tests
trend/stc_test.go
Added TestSlowStochastic and TestStcFull exercising the new indicator constructors and Compute methods with channel iteration, timeout guards, CSV-based test data, and validation assertions.

Sequence Diagrams

sequenceDiagram
    participant Client
    participant SlowStochastic
    participant MovingMinMax
    participant SMA
    participant Output

    Client->>SlowStochastic: Compute(values)
    activate SlowStochastic
    SlowStochastic->>MovingMinMax: Buffer and track min/max over Period
    activate MovingMinMax
    MovingMinMax->>SlowStochastic: emit min/max windows
    deactivate MovingMinMax
    
    SlowStochastic->>SlowStochastic: Calculate FastK = 100 * (value - min) / (max - min)
    
    SlowStochastic->>SMA: Smooth FastK with KPeriod
    activate SMA
    SMA->>SlowStochastic: emit SlowK
    deactivate SMA
    
    SlowStochastic->>SMA: Smooth SlowK with DPeriod
    activate SMA
    SMA->>SlowStochastic: emit SlowD
    deactivate SMA
    
    SlowStochastic->>Output: return (SlowK channel, SlowD channel)
    deactivate SlowStochastic
    Client->>Output: consume results
Loading
sequenceDiagram
    participant Client
    participant Stc
    participant Apo
    participant MovingMinMax
    participant Stochastic
    participant Output

    Client->>Stc: Compute(values)
    activate Stc
    Stc->>Apo: Feed buffered values
    activate Apo
    Apo->>Stc: emit MACD values
    deactivate Apo
    
    Stc->>MovingMinMax: Track min/max of MACD over KPeriod
    activate MovingMinMax
    MovingMinMax->>Stc: emit min/max windows
    deactivate MovingMinMax
    
    Stc->>Stochastic: Calculate stochastic from MACD range
    activate Stochastic
    Stochastic->>Stc: emit stochastic result
    deactivate Stochastic
    
    Stc->>Stc: Scale result by 100
    
    Stc->>Output: return STC channel
    deactivate Stc
    Client->>Output: consume results
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~65 minutes

Poem

🐰 Two new trends now hop through our streams,
Slow Stochastic flows and STC dreams,
With channels chained and periods set just right,
Market signals gleaming oh so bright! ✨

πŸš₯ Pre-merge checks | βœ… 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
βœ… Passed checks (4 passed)
Check name Status Explanation
Title check βœ… Passed The title 'Trend: Schaff Trend Cycle (STC)' clearly and concisely summarizes the main change: adding a new STC indicator to the trend package.
Description check βœ… Passed The PR description follows the template with required sections (Describe Request, Fixed issue, Change Type) completed with appropriate details about the STC indicator implementation.
Linked Issues check βœ… Passed The code changes fully implement the STC indicator from issue #53, including the Stc type, constructors, Compute method, and supporting SlowStochastic indicator needed for STC calculation.
Out of Scope Changes check βœ… Passed All changes directly support the STC indicator implementation: new Stc and SlowStochastic types, Apo.IdlePeriod method for idle period exposure, documentation updates, and comprehensive tests.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • πŸ“ Generate docstrings (stacked PR)
  • πŸ“ Generate docstrings (commit on current branch)
πŸ§ͺ Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch issue-53

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❀️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov-commenter
Copy link

Codecov Report

❌ Patch coverage is 80.64516% with 18 lines in your changes missing coverage. Please review.
βœ… Project coverage is 89.82%. Comparing base (2312e55) to head (4427298).

Files with missing lines Patch % Lines
trend/stc.go 83.01% 9 Missing ⚠️
trend/slow_stochastic.go 81.08% 7 Missing ⚠️
trend/apo.go 33.33% 2 Missing ⚠️

❌ Your project status has failed because the head coverage (89.82%) is below the target coverage (90.00%). You can increase the head coverage or adjust the target coverage.

Additional details and impacted files
@@            Coverage Diff             @@
##           master     #301      +/-   ##
==========================================
- Coverage   89.87%   89.82%   -0.05%     
==========================================
  Files         196      198       +2     
  Lines        5381     5473      +92     
==========================================
+ Hits         4836     4916      +80     
- Misses        477      491      +14     
+ Partials       68       66       -2     

β˜” View full report in Codecov by Sentry.
πŸ“’ Have feedback on the report? Share it here.

πŸš€ New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (2)
trend/stc.go (1)

92-135: Stochastic field used only for configuration, not for Compute.

The Stc.Compute method manually re-implements the stochastic calculation (movingMin, movingMax, divide, SMA) instead of delegating to s.Stochastic.Compute(). The Stochastic field is only used to access .Period, .Sma, and .IdlePeriod(). This creates a maintenance risk: if Stochastic.Compute logic changes, Stc won't pick up the changes. Consider either delegating to s.Stochastic.Compute() and working with its returned channels, or replacing the *Stochastic[T] field with the raw configuration values (period, smaPeriod) to make the decoupling explicit.

πŸ€– Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@trend/stc.go` around lines 92 - 135, Stc.Compute currently re-implements the
stochastic math instead of using the existing Stochastic implementation;
refactor either to call s.Stochastic.Compute(...) to obtain the stochastic
output channels (kValues and d) and use those channels (respecting
s.Stochastic.IdlePeriod() and s.Stochastic.Sma.IdlePeriod()) in the later
macd/k/d math, or replace the s.Stochastic field with explicit config values
(Period, SmaPeriod, IdlePeriod) and remove the local movingMin/movingMax/Sma
code; update references in Stc.Compute (where movingMin, movingMax, kValues, d,
kDuplicate, and related helper.Skip calls are used) to use the stochastic
Compute output or the new config fields so the STC logic delegates to the
canonical Stochastic implementation.
trend/slow_stochastic.go (1)

79-85: Division by zero when all values in the window are equal.

When highest == lowest (flat price window), helper.Divide will produce +Inf or NaN for float types. This is consistent with the existing Stochastic[T].Compute behavior in this codebase, but worth noting as a known edge case.

πŸ€– Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@trend/slow_stochastic.go` around lines 79 - 85, The current computation for
fastK can divide by zero when highest == lowest (flat window) causing +Inf/NaN;
update the logic in the fastK calculation (around fastK, helper.Divide, highest,
lowest, skipped, lowestSplice) to check if highest == lowest first and handle
that case (e.g., set fastK to 0.0 or another defined fallback) instead of
performing the Divide; mirror the safe behavior used by Stochastic[T].Compute so
the code returns a stable finite value rather than Inf/NaN.
πŸ€– Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@trend/stc_test.go`:
- Around line 54-78: TestStcFull is only a smoke test that asserts len(slice)>0
and never validates numeric results or other constructors/behaviors; update
tests to (1) add assertions using helper.CheckEquals to compare computed STC
values against expected K/D/Value columns from testdata/stochastic.csv using the
existing TestStcFull flow (read CSV via helper.ReadFromCsvFile, map values, call
Stc.Compute on trend.NewStcWithPeriod/ trend.NewStc()), (2) add separate tests
that instantiate default constructor NewStc() and
NewSlowStochasticWithPeriod(...) and assert their IdlePeriod() returns the
expected idle length and that Compute produces identical results where
applicable, and (3) exercise SlowStochastic.IdlePeriod and Stc.IdlePeriod
methods; reference the functions/types NewStcWithPeriod, NewStc,
NewSlowStochasticWithPeriod, Stc.Compute, SlowStochastic, IdlePeriod, and
helper.CheckEquals when locating code to change.
- Around line 15-52: TestSlowStochastic currently only checks that a value is
produced and uses a nondeterministic select that can return on first channel
close leaving the other channel/driving goroutine dangling; update the test to
drain actualK and actualD deterministically (do not use a select over both) by
converting each channel to a slice (use helper.ChanToSlice or explicit drains),
load expected K and D values from the existing CSV fixture, apply
helper.RoundDigits as needed, and assert equality with helper.CheckEquals
against trend.NewSlowStochastic()[s].Compute’s outputs (actualK, actualD);
ensure both channels are fully consumed so no goroutine leaks and use
helper.CheckEquals for all value assertions to meet the coding guidelines.

In `@trend/stc.go`:
- Around line 128-134: The expression computing STC can divide by zero when
Subtract(d, kValues) == 0; update the logic around MultiplyBy/Divide/Subtract
(references: macdForStc, kValues, d, helper.Subtract, helper.Divide,
helper.MultiplyBy) to guard the denominator: detect exact or near-zero
Subtract(d, kValues) (use a small epsilon like 1e-8) and handle that case
explicitly (e.g., return a sensible fallback such as 0 or the prior STC value,
or perform the division with epsilon) to avoid producing +Inf/NaN.
- Around line 25-38: The current STC doc/formula is incorrect: replace the
single-ratio formula in the Stc implementation with the standard Schaff Trend
Cycle two-stage stochastic smoothing, or explicitly mark this as a custom
variant; specifically, update the logic in the Stc type/methods (look for
functions/identifiers like Stc, Calculate/Compute, MACD, stochastic, %K/%D) so
that you compute MACD first, then apply a first stochastic to MACD to produce K1
and smooth it with an EMA (call it PF), then apply a second stochastic to PF to
produce K2 and smooth that with an EMA to produce STC, finally scale/clip STC to
the 0–100 range; if you intentionally want the previous ratio behavior instead,
change the comments/docstring to state this is a custom non-standard variant and
document its differences from the canonical two-stage stochastic STC.

---

Nitpick comments:
In `@trend/slow_stochastic.go`:
- Around line 79-85: The current computation for fastK can divide by zero when
highest == lowest (flat window) causing +Inf/NaN; update the logic in the fastK
calculation (around fastK, helper.Divide, highest, lowest, skipped,
lowestSplice) to check if highest == lowest first and handle that case (e.g.,
set fastK to 0.0 or another defined fallback) instead of performing the Divide;
mirror the safe behavior used by Stochastic[T].Compute so the code returns a
stable finite value rather than Inf/NaN.

In `@trend/stc.go`:
- Around line 92-135: Stc.Compute currently re-implements the stochastic math
instead of using the existing Stochastic implementation; refactor either to call
s.Stochastic.Compute(...) to obtain the stochastic output channels (kValues and
d) and use those channels (respecting s.Stochastic.IdlePeriod() and
s.Stochastic.Sma.IdlePeriod()) in the later macd/k/d math, or replace the
s.Stochastic field with explicit config values (Period, SmaPeriod, IdlePeriod)
and remove the local movingMin/movingMax/Sma code; update references in
Stc.Compute (where movingMin, movingMax, kValues, d, kDuplicate, and related
helper.Skip calls are used) to use the stochastic Compute output or the new
config fields so the STC logic delegates to the canonical Stochastic
implementation.

Comment on lines +15 to +52
func TestSlowStochastic(t *testing.T) {
resultChan := make(chan float64, 10)
go func() {
values := []float64{
100, 102, 101, 103, 105, 104, 106, 108, 107, 109,
110, 111, 109, 112, 113, 115, 114, 116, 118, 117,
119, 120, 118, 121, 122, 120, 123, 125, 124, 126,
}

input := helper.SliceToChan(values)
s := trend.NewSlowStochastic[float64]()
actualK, actualD := s.Compute(input)

for {
select {
case v, ok := <-actualK:
if !ok {
return
}
resultChan <- v
case v, ok := <-actualD:
if !ok {
return
}
resultChan <- v
case <-time.After(2 * time.Second):
return
}
}
}()

select {
case v := <-resultChan:
t.Logf("got value: %v", v)
case <-time.After(2 * time.Second):
t.Fatal("timeout - no values produced")
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

TestSlowStochastic lacks value assertions and has a flawed channel consumption pattern.

  1. No correctness validation: The test only checks that at least one value is produced. It doesn't compare outputs against expected values using helper.CheckEquals / helper.RoundDigits, which is required by coding guidelines.

  2. Nondeterministic select over K and D: The select on lines 28–42 returns on the first channel close, potentially leaving the other channel (and its upstream goroutines) dangling. If actualK closes before actualD is drained, goroutines writing to actualD will leak.

Consider following the existing test pattern in the codebase: load expected values from a CSV, drain each channel independently (or use helper.ChanToSlice), and compare with helper.CheckEquals.

As per coding guidelines, "Use helper.CheckEquals for assertions in tests" and "Achieve 100% code coverage for all indicators".

πŸ€– Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@trend/stc_test.go` around lines 15 - 52, TestSlowStochastic currently only
checks that a value is produced and uses a nondeterministic select that can
return on first channel close leaving the other channel/driving goroutine
dangling; update the test to drain actualK and actualD deterministically (do not
use a select over both) by converting each channel to a slice (use
helper.ChanToSlice or explicit drains), load expected K and D values from the
existing CSV fixture, apply helper.RoundDigits as needed, and assert equality
with helper.CheckEquals against trend.NewSlowStochastic()[s].Compute’s outputs
(actualK, actualD); ensure both channels are fully consumed so no goroutine
leaks and use helper.CheckEquals for all value assertions to meet the coding
guidelines.

Comment on lines +54 to +78
func TestStcFull(t *testing.T) {
type Data struct {
Value float64
K float64
D float64
}

input, err := helper.ReadFromCsvFile[Data]("testdata/stochastic.csv")
if err != nil {
t.Fatal(err)
}

values := helper.Map(input, func(d *Data) float64 { return d.Value })

stc := trend.NewStcWithPeriod[float64](5, 10, 5, 3)
result := stc.Compute(values)

slice := helper.ChanToSlice(result)

t.Logf("STC generated %d values", len(slice))

if len(slice) == 0 {
t.Fatal("no results generated")
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

TestStcFull is a smoke test without value assertions.

The test reads a CSV with K and D columns but never uses them for validation. It only asserts len(slice) > 0. This doesn't verify computational correctness and won't catch regressions.

Additionally, there are no tests for:

  • NewStc() (default constructor)
  • NewSlowStochasticWithPeriod()
  • IdlePeriod() on both SlowStochastic and Stc

As per coding guidelines, "Achieve 100% code coverage for all indicators" and "Use helper.CheckEquals for assertions in tests".

πŸ€– Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@trend/stc_test.go` around lines 54 - 78, TestStcFull is only a smoke test
that asserts len(slice)>0 and never validates numeric results or other
constructors/behaviors; update tests to (1) add assertions using
helper.CheckEquals to compare computed STC values against expected K/D/Value
columns from testdata/stochastic.csv using the existing TestStcFull flow (read
CSV via helper.ReadFromCsvFile, map values, call Stc.Compute on
trend.NewStcWithPeriod/ trend.NewStc()), (2) add separate tests that instantiate
default constructor NewStc() and NewSlowStochasticWithPeriod(...) and assert
their IdlePeriod() returns the expected idle length and that Compute produces
identical results where applicable, and (3) exercise SlowStochastic.IdlePeriod
and Stc.IdlePeriod methods; reference the functions/types NewStcWithPeriod,
NewStc, NewSlowStochasticWithPeriod, Stc.Compute, SlowStochastic, IdlePeriod,
and helper.CheckEquals when locating code to change.

Comment on lines +25 to +38
// Stc represents the configuration parameters for calculating the
// Schaff Trend Cycle (STC) indicator. It combines MACD with
// stochastic oscillators to identify trend direction and potential
// entry points.
//
// EMA1 = EMA(values, fastPeriod)
// EMA2 = EMA(values, slowPeriod)
// MACD = EMA1 - EMA2
//
// %K = Stochastic %K of MACD with kPeriod
// %D = Stochastic %D of MACD with dPeriod
//
// STC = 100 * (MACD - %K) / (%D - %K)
//
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

Schaff Trend Cycle STC formula standard algorithm stochastic MACD

πŸ’‘ Result:

Schaff Trend Cycle (STC): β€œstochastic MACD” standard algorithm

A common/reference implementation (Doug Schaff’s original style) is:

Inputs

  • TCLen = cycle length / stochastic lookback (often 10)
  • MA1 = fast EMA length (often 23)
  • MA2 = slow EMA length (often 50)
  • Ξ± = smoothing factor (often 0.5)
  • Output is bounded 0–100; common signal levels: 25 / 75. [2]

Step-by-step formula

Let src be price (typically close).

1) MACD line (no signal line needed)

[
XMAC_t = EMA(src, MA1)_t - EMA(src, MA2)_t
]
(Trading code often just calls this MACD(c, MA1, MA2).) [1]

2) 1st stochastic of MACD (Fast %K), then exponential smoothing

[
L1_t = \min(XMAC_{t-TCLen+1 \dots t})
]
[
H1_t = \max(XMAC_{t-TCLen+1 \dots t})
]
[
K1_t =
\begin{cases}
100\cdot \dfrac{XMAC_t - L1_t}{H1_t - L1_t}, & H1_t \ne L1_t \
K1_{t-1}, & H1_t = L1_t
\end{cases}
]
[
PF_t = PF_{t-1} + \alpha,(K1_t - PF_{t-1})
]
This PF is the smoothed stochastic of the MACD. [1]

3) 2nd stochastic of that smoothed series, then exponential smoothing β†’ STC

[
L2_t = \min(PF_{t-TCLen+1 \dots t})
]
[
H2_t = \max(PF_{t-TCLen+1 \dots t})
]
[
K2_t =
\begin{cases}
100\cdot \dfrac{PF_t - L2_t}{H2_t - L2_t}, & H2_t \ne L2_t \
K2_{t-1}, & H2_t = L2_t
\end{cases}
]
[
STC_t = STC_{t-1} + \alpha,(K2_t - STC_{t-1})
]
In the EasyLanguage reference, the final smoothed value is called PFF, and STC = PFF. [1]


Default parameters you’ll often see

Many trading-platform guides use (TCLen, MA1, MA2) = (10, 23, 50) and interpret crosses of 25/75 as cycle/trend change signals. [2]

Sources: EasyLanguage reference code (Traders.com, Apr 2010) [1]; parameter/level conventions (Forex-Indicators.net) [2].


🏁 Script executed:

cd /dev/null && find . -name "stc.go" -type f 2>/dev/null | head -5

Repository: cinar/indicator

Length of output: 108


🏁 Script executed:

cat -n trend/stc.go | head -150

Repository: cinar/indicator

Length of output: 4587


STC implementation uses non-standard formula that does not match the Schaff Trend Cycle algorithm.

The documented formula STC = 100 * (MACD - %K) / (%D - %K) differs fundamentally from the standard Schaff Trend Cycle, which applies two rounds of stochastic smoothing with exponential averaging to the MACD line:

  1. First stochastic: K1 = stochastic(MACD) then exponentially smoothed β†’ PF
  2. Second stochastic: K2 = stochastic(PF) then exponentially smoothed β†’ STC

The result is naturally bounded 0–100.

The implemented formula calculates a ratio of differences (MACD - %K) / (%D - %K) which is unbounded and not a stochastic transformation. This produces a fundamentally different output than the standard algorithm. Verify the intended algorithm and either update the implementation to use proper double stochastic smoothing or document this as a custom variant.

πŸ€– Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@trend/stc.go` around lines 25 - 38, The current STC doc/formula is incorrect:
replace the single-ratio formula in the Stc implementation with the standard
Schaff Trend Cycle two-stage stochastic smoothing, or explicitly mark this as a
custom variant; specifically, update the logic in the Stc type/methods (look for
functions/identifiers like Stc, Calculate/Compute, MACD, stochastic, %K/%D) so
that you compute MACD first, then apply a first stochastic to MACD to produce K1
and smooth it with an EMA (call it PF), then apply a second stochastic to PF to
produce K2 and smooth that with an EMA to produce STC, finally scale/clip STC to
the 0–100 range; if you intentionally want the previous ratio behavior instead,
change the comments/docstring to state this is a custom non-standard variant and
document its differences from the canonical two-stage stochastic STC.

Comment on lines +128 to +134
return helper.MultiplyBy(
helper.Divide(
helper.Subtract(macdForStc, kValues),
helper.Subtract(d, kValues),
),
100,
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟑 Minor

Division by zero when %D == %K.

When d equals kValues, the denominator Subtract(d, kValues) is zero, producing +Inf or NaN. Unlike the stochastic (value - min) / (max - min) pattern where a zero range is uncommon, %D converging to %K can happen in trending markets. Consider whether this needs a guard.

πŸ€– Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@trend/stc.go` around lines 128 - 134, The expression computing STC can divide
by zero when Subtract(d, kValues) == 0; update the logic around
MultiplyBy/Divide/Subtract (references: macdForStc, kValues, d, helper.Subtract,
helper.Divide, helper.MultiplyBy) to guard the denominator: detect exact or
near-zero Subtract(d, kValues) (use a small epsilon like 1e-8) and handle that
case explicitly (e.g., return a sensible fallback such as 0 or the prior STC
value, or perform the division with epsilon) to avoid producing +Inf/NaN.

@cinar cinar merged commit 7aca34b into master Feb 22, 2026
6 checks passed
@cinar cinar deleted the issue-53 branch February 22, 2026 00:35
@github-actions github-actions bot locked and limited conversation to collaborators Feb 22, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Trend: Schaff Trend Cycle (STC)

2 participants