ICT Propulsion Block
swing_length = 3 | mitigation_price = close Overview
ICT Propulsion Block tracks the most recent bullish and bearish order-block structure on every bar. For each side it emits the current block high and low, whether the current block is a regular order block or a propulsion block, whether that block is still active, whether it has been mitigated, and whether a new block was created on the current bar.
The implementation works on full OHLC input, validates bars with finite open, high, low, and close values, and resets its internal swing and block state when it encounters an invalid bar. Bullish and bearish block outputs are emitted as twelve parallel series, which makes the indicator suitable for chart overlays, screening, and batch parameter sweeps.
Defaults: swing_length = 3 and mitigation_price = "close".
Implementation Examples
Calculate bullish and bearish propulsion-block state from OHLC slices or from the shared Candles type:
use vector_ta::indicators::ict_propulsion_block::{
ict_propulsion_block, IctPropulsionBlockInput, IctPropulsionBlockMitigationPrice,
IctPropulsionBlockParams,
};
use vector_ta::utilities::data_loader::{Candles, read_candles_from_csv};
let open = vec![100.0, 101.0, 100.5, 102.0, 103.0];
let high = vec![101.0, 102.0, 101.5, 103.5, 104.0];
let low = vec![99.5, 100.0, 99.8, 101.5, 102.0];
let close = vec![100.8, 100.4, 101.2, 103.2, 103.6];
let input = IctPropulsionBlockInput::from_slices(
&open,
&high,
&low,
&close,
IctPropulsionBlockParams {
swing_length: Some(3),
mitigation_price: Some(IctPropulsionBlockMitigationPrice::Close),
},
);
let out = ict_propulsion_block(&input)?;
// Twelve aligned output series
println!("{:?}", out.bullish_high);
println!("{:?}", out.bullish_kind);
println!("{:?}", out.bearish_mitigated);
// Candles helper with default params
let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let out = ict_propulsion_block(&IctPropulsionBlockInput::with_default_candles(&candles))?; API Reference
Input Methods ▼
IctPropulsionBlockInput::from_candles(&Candles, IctPropulsionBlockParams) -> IctPropulsionBlockInput
IctPropulsionBlockInput::from_slices(&[f64], &[f64], &[f64], &[f64], IctPropulsionBlockParams) -> IctPropulsionBlockInput
IctPropulsionBlockInput::with_default_candles(&Candles) -> IctPropulsionBlockInput Parameters Structure ▼
pub enum IctPropulsionBlockMitigationPrice {
Close,
Wick,
}
pub struct IctPropulsionBlockParams {
pub swing_length: Option<usize>,
pub mitigation_price: Option<IctPropulsionBlockMitigationPrice>,
}
// Defaults
// swing_length = 3
// mitigation_price = Close Output Structure ▼
pub struct IctPropulsionBlockOutput {
pub bullish_high: Vec<f64>,
pub bullish_low: Vec<f64>,
pub bullish_kind: Vec<f64>,
pub bullish_active: Vec<f64>,
pub bullish_mitigated: Vec<f64>,
pub bullish_new: Vec<f64>,
pub bearish_high: Vec<f64>,
pub bearish_low: Vec<f64>,
pub bearish_kind: Vec<f64>,
pub bearish_active: Vec<f64>,
pub bearish_mitigated: Vec<f64>,
pub bearish_new: Vec<f64>,
}
// kind values:
// 0.0 = no current block snapshot
// 1.0 = regular order block
// 2.0 = propulsion block
// active / mitigated / new values:
// 1.0 = true
// 0.0 = false Builders, Batch Range, and Stream ▼
IctPropulsionBlockBuilder::new()exposesswing_length(),mitigation_price(),kernel(),apply(),apply_slices(), andinto_stream().IctPropulsionBlockStream::update(open, high, low, close)returnsOption<(f64, ..., f64)>with 12 values in the same order as the output struct.IctPropulsionBlockBatchRangesweepsswing_length: (start, end, step)andmitigation_price: (include_close, include_wick).IctPropulsionBlockBatchBuilder::new()exposesswing_length_range(),mitigation_price_toggle(),kernel(),apply(), andapply_slices().- Batch output adds
combos,rows, andcols; each output vector is flattened row-major withrows * colsentries.
Validation, State, and NaNs ▼
- All four inputs must be non-empty and have matching lengths; otherwise the indicator returns
IctPropulsionBlockError::EmptyInputDataorDataLengthMismatch. - A valid bar requires finite
open,high,low, andclosevalues withhigh >= low. swing_lengthmust be greater than zero.- If every bar is invalid, the indicator returns
IctPropulsionBlockError::AllValuesNaN. - When an invalid bar appears during calculation, that bar is written as
NaNacross all twelve outputs and the internal swing/block state is reset. mitigation_price = closeuses close-through-block checks for mitigation;wickuses high/low wick breaches.
Error Handling ▼
use vector_ta::indicators::ict_propulsion_block::IctPropulsionBlockError;
match ict_propulsion_block(&input) {
Ok(out) => {
println!("{:?}", out.bullish_high);
}
Err(IctPropulsionBlockError::EmptyInputData) =>
eprintln!("input slices cannot be empty"),
Err(IctPropulsionBlockError::DataLengthMismatch { open, high, low, close }) =>
eprintln!("length mismatch: open={open}, high={high}, low={low}, close={close}"),
Err(IctPropulsionBlockError::InvalidSwingLength { swing_length }) =>
eprintln!("invalid swing length: {}", swing_length),
Err(IctPropulsionBlockError::InvalidMitigationPrice { mitigation_price }) =>
eprintln!("invalid mitigation price: {}", mitigation_price),
Err(IctPropulsionBlockError::AllValuesNaN) =>
eprintln!("all bars were invalid"),
Err(IctPropulsionBlockError::InvalidKernelForBatch(kernel)) =>
eprintln!("invalid batch kernel: {:?}", kernel),
Err(e) => eprintln!("ICT Propulsion Block error: {}", e),
} Python Bindings
Basic Usage ▼
Python exposes ict_propulsion_block(open, high, low, close, swing_length=3, mitigation_price="close", kernel=None) and returns twelve NumPy arrays in the same field order as the Rust output struct.
import numpy as np
from vector_ta import ict_propulsion_block
open_ = np.array([100.0, 101.0, 100.5, 102.0, 103.0], dtype=np.float64)
high = np.array([101.0, 102.0, 101.5, 103.5, 104.0], dtype=np.float64)
low = np.array([99.5, 100.0, 99.8, 101.5, 102.0], dtype=np.float64)
close = np.array([100.8, 100.4, 101.2, 103.2, 103.6], dtype=np.float64)
(
bullish_high,
bullish_low,
bullish_kind,
bullish_active,
bullish_mitigated,
bullish_new,
bearish_high,
bearish_low,
bearish_kind,
bearish_active,
bearish_mitigated,
bearish_new,
) = ict_propulsion_block(open_, high, low, close, swing_length=3, mitigation_price="close") Streaming Real-time Updates ▼
The Python stream class is IctPropulsionBlockStream. Its update() method returns the current twelve-field snapshot or None for an invalid bar.
from vector_ta import IctPropulsionBlockStream
stream = IctPropulsionBlockStream(swing_length=3, mitigation_price="wick")
for open_, high, low, close in feed:
out = stream.update(open_, high, low, close)
if out is not None:
bullish_high = out[0]
bearish_new = out[11]
print(bullish_high, bearish_new) Batch Processing ▼
ict_propulsion_block_batch returns a dict with twelve 2D output arrays plus grid metadata.
import numpy as np
from vector_ta import ict_propulsion_block_batch
result = ict_propulsion_block_batch(
open_,
high,
low,
close,
swing_length_range=(3, 7, 2),
mitigation_price_toggle=(True, True),
)
bullish_high = result["bullish_high"]
bearish_kind = result["bearish_kind"]
rows = result["rows"]
cols = result["cols"]
swing_lengths = result["swing_lengths"]
mitigation_prices = result["mitigation_prices"] JavaScript/WASM Bindings
Basic Usage ▼
WASM exports ict_propulsion_block(open, high, low, close, swing_length, mitigation_price) and returns an object with the same twelve output keys as Rust.
import { ict_propulsion_block } from 'vectorta-wasm';
const open = new Float64Array([100.0, 101.0, 100.5, 102.0, 103.0]);
const high = new Float64Array([101.0, 102.0, 101.5, 103.5, 104.0]);
const low = new Float64Array([99.5, 100.0, 99.8, 101.5, 102.0]);
const close = new Float64Array([100.8, 100.4, 101.2, 103.2, 103.6]);
const out = ict_propulsion_block(open, high, low, close, 3, 'close');
console.log(out.bullish_high);
console.log(out.bullish_kind);
console.log(out.bearish_new); Memory-Efficient Operations ▼
For host-array input plus zero-copy output writes, use ict_propulsion_block_into_host with a buffer allocated by ict_propulsion_block_alloc. The output buffer stores 12 consecutive lanes of length len.
import {
ict_propulsion_block_alloc,
ict_propulsion_block_free,
ict_propulsion_block_into_host,
memory,
} from 'vectorta-wasm';
const len = close.length;
const outPtr = ict_propulsion_block_alloc(len);
ict_propulsion_block_into_host(open, high, low, close, outPtr, 3, 'wick');
const flat = new Float64Array(memory.buffer, outPtr, len * 12);
const bullishHigh = flat.slice(0, len);
const bullishLow = flat.slice(len, len * 2);
const bullishKind = flat.slice(len * 2, len * 3);
const bearishNew = flat.slice(len * 11, len * 12);
ict_propulsion_block_free(outPtr, len); Batch Processing ▼
Batch WASM uses ict_propulsion_block_batch with a config object containing swing_length_range and mitigation_price_toggle.
import { ict_propulsion_block_batch } from 'vectorta-wasm';
const batch = ict_propulsion_block_batch(open, high, low, close, {
swing_length_range: [3, 7, 2],
mitigation_price_toggle: [true, true],
});
console.log(batch.rows, batch.cols);
console.log(batch.combos);
console.log(batch.bullish_high);
console.log(batch.bearish_kind); CUDA Bindings (Rust)
Additional details for the CUDA bindings can be found inside the VectorTA repository.
Performance Analysis
Across sizes, Rust CPU runs about 1.14× faster than Tulip C in this benchmark.
AMD Ryzen 9 9950X (CPU) | NVIDIA RTX 4090 (GPU)
Related Indicators
Average Directional Index
Technical analysis indicator
Average Directional Movement Index Rating
Technical analysis indicator
Alligator
Technical analysis indicator
Aroon
Technical analysis indicator
Aroon Oscillator
Technical analysis indicator
Chande Momentum Oscillator
Technical analysis indicator