feat(dynamics): add PlusDI, MinusDI, PlusDM, MinusDM indicators

Complete thin Dx-composition wrapper indicators with full test coverage:

- PlusDi/MinusDi: Directional Indicator wrappers (DiPlus/DiMinus from Dx)
- PlusDm/MinusDm: Directional Movement wrappers (DmPlus/DmMinus from Dx)
- Individual validation tests per indicator directory (TALib, Skender, bounds)
- Combined unit tests (DiDm.Tests.cs) and validation tests (DiDm.Validation.Tests.cs)
- Quantower wrappers + tests for all 4 indicators
- PineScript v6 implementations with compensated RMA
- Normalized .md documentation for all indicators and categories
- 182 tests passing, 0 failures
This commit is contained in:
Miha Kralj
2026-03-11 20:21:52 -07:00
parent 56b86bebfb
commit 33d20f2a18
437 changed files with 4589 additions and 2792 deletions
+2 -48
View File
@@ -1,5 +1,7 @@
# STC: Schaff Trend Cycle
> *Schaff Trend Cycle applies double stochastic smoothing to MACD, compressing a trend indicator into an oscillator's bounded range.*
| Property | Value |
| ---------------- | -------------------------------- |
| **Category** | Oscillator |
@@ -91,54 +93,6 @@ Smoothing options:
| $s$ | slowLength | 50 | $s > f$ |
| — | smoothing | EMA | None / EMA / Sigmoid / Digital |
### Pseudo-code
```
Initialize:
ema_fast = ema_slow = first price
α_f = 2 / (fastLength + 1)
α_s = 2 / (slowLength + 1)
α_d = 2 / (dPeriod + 1)
macd_buf = RingBuffer(kPeriod)
d1_buf = RingBuffer(kPeriod)
%D₁ = 0
bar_count = 0
On each bar (price, isNew):
if !isNew: restore previous state
// Step 1: MACD
ema_fast = FMA(ema_fast, 1 - α_f, α_f × price)
ema_slow = FMA(ema_slow, 1 - α_s, α_s × price)
macd = ema_fast - ema_slow
// Step 2: First Stochastic
macd_buf.Add(macd)
macd_max = Max(macd_buf)
macd_min = Min(macd_buf)
range1 = macd_max - macd_min
%K₁ = range1 > 0 ? 100 × (macd - macd_min) / range1 : prev_%K₁
// Step 3: First Smoothing
%D₁ = FMA(%D₁, 1 - α_d, α_d × %K₁)
// Step 4: Second Stochastic
d1_buf.Add(%D₁)
d1_max = Max(d1_buf)
d1_min = Min(d1_buf)
range2 = d1_max - d1_min
%K₂ = range2 > 0 ? 100 × (%D₁ - d1_min) / range2 : prev_%K₂
// Step 5: Final Smoothing
switch smoothing:
None: STC = %K₂
EMA: STC = FMA(prev_STC, 1 - α_d, α_d × %K₂)
Sigmoid: STC = 100 / (1 + exp(-0.1 × (%K₂ - 50)))
Digital: STC = %K₂ ≥ 50 ? 100 : 0
output = Clamp(STC, 0, 100)
```
### Signal Characteristics
| Condition | Output Behavior |