PlusDm
Wilder's Plus Directional Movement (
PLUS_DM) — the Wilder-smoothed running total of the raw+DMthat feedsAdxandPlusDi, exposed standalone.
Quick reference
| Field | Value |
|---|---|
| Family | Trend & Directional |
| Input type | Candle (uses high, low) |
| Output type | f64 |
| Output range | >= 0 (a smoothed sum of up-moves) |
| Default parameters | period is required |
| Warmup period | period (first value at candle index period) |
| Interpretation | The accumulated strength of upward directional movement over the window. |
Formula
The raw plus directional movement of a bar is
up = high − high_prev
down = low_prev − low
+DM = up if (up > down and up > 0) else 0PlusDm returns the Wilder-smoothed running total of that raw +DM. The first period raw values seed the sum; from then on each update applies the Wilder recursion:
smoothed = smoothed − smoothed / period + raw_plus_dmThis is the same +DM accumulation that drives Adx and PlusDi. The shared directional_movement helper lives in crates/wickra-core/src/indicators/adx.rs; the smoothing wrapper is crates/wickra-core/src/indicators/plus_dm.rs.
Parameters
| Name | Type | Default | Valid range | Description | Source |
|---|---|---|---|---|---|
period | usize | none | >= 1 | Wilder smoothing length. period = 0 errors with Error::PeriodZero. | plus_dm.rs:49 |
Inputs / Outputs
From crates/wickra-core/src/indicators/plus_dm.rs:
use wickra::{Indicator, PlusDm, Candle};
// PlusDm: Input = Candle, Output = f64
const _: fn(&mut PlusDm, Candle) -> Option<f64> = <PlusDm as Indicator>::update;PlusDm is a candle-input indicator that reads high and low. In Python the streaming update accepts a candle; the batch helper takes high, low, close numpy arrays and returns a 1-D numpy.ndarray (NaN for warmup). Node and WASM expose update(high, low, close) and the matching batch.
Warmup
PlusDm::new(period).warmup_period() == period (the accessors_report_config unit test pins warmup_period() == 7 for period = 7). Because a bar's directional movement needs the previous bar, the first emitted value appears at candle index period — the (period + 1)-th candle. The seeds_then_smooths_a_constant_plus_dm test pins this: for period = 3 the first three outputs are None and the first value lands at index 3.
Edge cases
- Down moves contribute zero. On a bar whose down-move dominates, the raw
+DMis0and only the Wilder decay applies. The unit testdown_moves_contribute_zeropins this. - Constant up-move. A series with a steady
+1up-move per bar seeds to the sum of three unit moves (3.0) and the Wilder step3 − 3/3 + 1 = 3holds it there. The unit testseeds_then_smooths_a_constant_plus_dmpins this. - Zero period.
PlusDm::new(0)returnsErr(Error::PeriodZero). The unit testrejects_zero_periodpins this. - Reset.
dm.reset()restores the initial state (no previous bar, empty seed). The unit testreset_restores_initial_statepins this.
Examples
Rust
use wickra::{BatchExt, Candle, Indicator, PlusDm};
fn main() -> Result<(), Box<dyn std::error::Error>> {
// high +1/bar, low +0.5/bar → +DM is a steady 1.0 per bar.
let c = |h: f64, l: f64, cl: f64| Candle::new(cl, h, l, cl, 1.0, 0).unwrap();
let candles: Vec<Candle> = (0..5)
.map(|i| c(11.0 + i as f64, 9.0 + 0.5 * i as f64, 10.0 + i as f64))
.collect();
let mut dm = PlusDm::new(3)?;
println!("{:?}", dm.batch(&candles));
Ok(())
}Output:
[None, None, None, Some(3.0), Some(3.0)]The seed at index 3 is the sum of three unit +DM values (3.0); the Wilder step at index 4 is 3 − 3/3 + 1 = 3. This matches the seeds_then_smooths_a_constant_plus_dm unit test in crates/wickra-core/src/indicators/plus_dm.rs.
Python
import numpy as np
import wickra as ta
dm = ta.PlusDm(3)
high = np.array([11.0, 12.0, 13.0, 14.0, 15.0])
low = np.array([9.0, 9.5, 10.0, 10.5, 11.0])
close = np.array([10.0, 11.0, 12.0, 13.0, 14.0])
print(dm.batch(high, low, close))Output:
[nan nan nan 3. 3.]Node
const ta = require('wickra');
const dm = new ta.PlusDm(3);
const bars = [[11, 9], [12, 9.5], [13, 10], [14, 10.5], [15, 11]];
for (const [h, l] of bars) console.log(dm.update(h, l, l));Output:
null
null
null
3
3Interpretation
PlusDm measures how much upward directional pressure has accumulated. On its own it is rarely traded — its purpose is to be normalised by true range into PlusDi and combined with MinusDi into the directional system behind Adx. Expose it standalone when you want the un-normalised up-move accumulation as a feature, or to build a custom directional ratio.
Common pitfalls
- Comparing magnitudes across instruments.
+DMis in raw price units, so it scales with the instrument's price and volatility. UsePlusDi(normalised by true range,0–100) for cross-instrument comparison. - Expecting it before
period + 1bars. The first candle only records the previous bar; no+DMexists yet.
References
J. Welles Wilder Jr., New Concepts in Technical Trading Systems (1978), matching TA-Lib's PLUS_DM.
See also
- Indicator-MinusDm — the bearish counterpart.
- Indicator-PlusDi —
+DMnormalised by true range. - Indicator-Dx / Indicator-Adx — the full directional system.
- Indicators-Overview — the full taxonomy.