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
+83 -18
View File
@@ -1,27 +1,92 @@
# PLUS_DM: Plus Directional Movement
Wilder-smoothed upward directional movement in price units (≥0).
> *+DM captures the raw upward price extension, smoothed by Wilder's RMA — the building block before normalization to +DI.*
## Introduction
Plus Directional Movement (+DM) measures the magnitude of upward price movement, smoothed using Wilder's method. Unlike +DI which normalizes by true range to produce a percentage, +DM outputs raw smoothed values in price units.
| Property | Value |
| ---------------- | -------------------------------- |
| **Category** | Dynamic |
| **Inputs** | OHLCV bar (TBar) |
| **Parameters** | `period` (default 14) |
| **Outputs** | Single series |
| **Output range** | ≥ 0 (price units) |
| **Warmup** | `period` bars |
| **PineScript** | [plusdm.pine](plusdm.pine) |
+DM captures when the current bar's high exceeds the previous bar's high by more than the previous bar's low exceeds the current bar's low. It is the raw building block of the Directional Movement System.
- Plus Directional Movement outputs the Wilder-smoothed upward directional movement in price units.
- Parameterized by `period` (default 14).
- Output range: ≥ 0 (price units, scales with instrument).
- Requires `period` bars of warmup before first valid output (IsHot = true).
- Validated against TA-Lib and Dx equivalence.
## Calculation
+DM = max(High - PrevHigh, 0) when High - PrevHigh > PrevLow - Low, else 0
Plus Directional Movement (+DM) measures the magnitude of upward price movement, smoothed using Wilder's method. Unlike +DI which normalizes by true range to produce a percentage, +DM outputs raw smoothed values in price units. +DM captures when the current bar's high exceeds the previous bar's high by more than the previous bar's low exceeds the current bar's low. It is the raw building block of the Directional Movement System — the unnormalized signal before division by True Range converts it to +DI.
Smoothed using Wilder's method: Smooth = Smooth - Smooth/N + Input
## Historical Context
## Parameters
| Parameter | Default | Range | Description |
| :--- | :--- | :--- | :--- |
| Period | 14 | 2-∞ | Wilder smoothing period |
J. Welles Wilder Jr. designed the Directional Movement System as a pipeline in *New Concepts in Technical Trading Systems* (1978). +DM is the first computational stage: a binary event detector that fires when upward range expansion dominates. Wilder's insight was that direction should be measured by range *extension*, not by close-to-close returns. A bar that pushes to a new high by more than it pushes to a new low registers as positive directional movement. The smoothed +DM series shows how much upward thrust is being sustained over the lookback period, in absolute price units.
## Interpretation
- **Rising +DM:** Increasing upward price extension
- **+DM > -DM:** Upward movement exceeds downward movement
- **Zero +DM:** No upward directional movement on the bar
- Values are in price units and scale with the instrument
## Architecture & Physics
## References
- Wilder, J. Welles Jr. "New Concepts in Technical Trading Systems" (1978)
### 1. Plus Directional Movement (Raw)
$$\text{UpMove} = H_t - H_{t-1}, \quad \text{DownMove} = L_{t-1} - L_t$$
$$+DM = \begin{cases} \text{UpMove} & \text{if UpMove} > \text{DownMove and UpMove} > 0 \\ 0 & \text{otherwise} \end{cases}$$
Only one of +DM or -DM can be non-zero per bar — the dominant direction wins.
### 2. Wilder Smoothing (RMA)
$$+DM_{\text{smooth}} = \text{RMA}(+DM, N), \quad \alpha = 1/N$$
### 3. Complexity
- **Time:** $O(1)$ per bar — recursive RMA update
- **Space:** $O(1)$ — scalar state only (delegates to Dx)
- **Warmup:** $N$ bars
## Mathematical Foundation
### Parameters
| Symbol | Parameter | Default | Constraint |
|--------|-----------|---------|------------|
| $N$ | period | 14 | $N \geq 2$ |
### Interpretation
| +DM Behavior | Signal |
|--------------|--------|
| Rising +DM | Increasing upward price extension |
| +DM > -DM | Upward movement exceeds downward movement |
| Zero +DM | No upward directional movement on the bar |
| Values scale with instrument | Compare within same instrument only |
+DM values are in price units and scale with the instrument. They cannot be compared across different instruments without normalization (which is what +DI provides).
## Performance Profile
### Operation Count (Streaming Mode)
+DM is a thin wrapper around Dx. The per-bar cost is identical to Dx (one property extraction after Dx completes its update).
**Post-warmup steady state (per bar):**
| Operation | Count | Cost (cycles) | Subtotal |
| :--- | :---: | :---: | :---: |
| Dx.Update (full pipeline) | 1 | 75 | 75 |
| Property extraction | 1 | 1 | 1 |
| **Total** | **2** | — | **~76 cycles** |
### Quality Metrics
| Metric | Score | Notes |
| :--- | :---: | :--- |
| **Accuracy** | 9/10 | Exact Dx delegation; FMA-precise RMA smoothing |
| **Timeliness** | 7/10 | N-bar warmup; responds to bar-level changes |
| **Smoothness** | 7/10 | Single RMA layer; moderate noise suppression |
| **Noise Rejection** | 7/10 | Wilder smoothing filters transient spikes |
## Resources
- Wilder, J.W. — *New Concepts in Technical Trading Systems* (Trend Research, 1978)
- PineScript reference: `plusdm.pine` in indicator directory