Market Structure Confluence

Parameters: swing_size = 10 | bos_confirmation = Candle Close | basis_length = 100 | atr_length = 14 | atr_smooth = 21 | vol_mult = 2

Overview

Market Structure Confluence consumes high, low, and close series and tracks pivot highs and pivot lows over a symmetric swing_size window. Each new pivot is labeled as higher high, lower high, higher low, or lower low by comparing it to the previous pivot of the same type. When price later breaks the last active swing, the indicator flags a bullish or bearish break of structure and classifies the break as either BOS or CHoCH depending on the prior break direction.

In parallel, the indicator builds a weighted moving average basis from close, computes ATR over atr_length, smooths that ATR with an SMA of length atr_smooth, and places upper_band and lower_band at basis ± vol_mult × smoothed ATR. The output includes structure direction, swing labels, BOS and CHoCH markers, and bullish or bearish arrow markers when price interacts with the active-side band while structure direction is already set.

Defaults: swing_size = 10, bos_confirmation = "Candle Close", basis_length = 100, atr_length = 14, atr_smooth = 21, vol_mult = 2.0.

Implementation Examples

Compute the full structure state from slices or candles:

use vector_ta::indicators::market_structure_confluence::{
    market_structure_confluence,
    MarketStructureConfluenceInput,
    MarketStructureConfluenceParams,
};
use vector_ta::utilities::data_loader::{Candles, read_candles_from_csv};

let params = MarketStructureConfluenceParams {
    swing_size: Some(10),
    bos_confirmation: Some("Candle Close".to_string()),
    basis_length: Some(100),
    atr_length: Some(14),
    atr_smooth: Some(21),
    vol_mult: Some(2.0),
};

let input = MarketStructureConfluenceInput::from_slices(&high, &low, &close, params);
let result = market_structure_confluence(&input)?;

println!("Basis latest: {:?}", result.basis.last());
println!("Bullish BOS latest: {:?}", result.bullish_bos.last());

let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let input = MarketStructureConfluenceInput::with_default_candles(&candles);
let result = market_structure_confluence(&input)?;
println!("Structure direction latest: {:?}", result.structure_direction.last());

API Reference

Input Methods
MarketStructureConfluenceInput::from_slices(&[f64], &[f64], &[f64], MarketStructureConfluenceParams)
MarketStructureConfluenceInput::from_candles(&Candles, MarketStructureConfluenceParams)
MarketStructureConfluenceInput::with_default_candles(&Candles)

Candle input always uses candle high, low, and close; there is no separate source selector.

Parameters Structure
pub struct MarketStructureConfluenceParams {
    pub swing_size: Option<usize>,          // default 10
    pub bos_confirmation: Option<String>,   // default "Candle Close"
    pub basis_length: Option<usize>,        // default 100
    pub atr_length: Option<usize>,          // default 14
    pub atr_smooth: Option<usize>,          // default 21
    pub vol_mult: Option<f64>,              // default 2.0
}
  • bos_confirmation accepts "Candle Close" or "Wicks".
  • swing_size must be at least 2 and fit inside the input as swing_size * 2 + 1.
  • basis_length, atr_length, and atr_smooth must be at least 1 and no larger than the data length.
  • vol_mult must be finite and at least 0.0.
Output Structure
pub struct MarketStructureConfluenceOutput {
    pub basis: Vec<f64>,
    pub upper_band: Vec<f64>,
    pub lower_band: Vec<f64>,
    pub structure_direction: Vec<f64>,
    pub bullish_arrow: Vec<f64>,
    pub bearish_arrow: Vec<f64>,
    pub bullish_change: Vec<f64>,
    pub bearish_change: Vec<f64>,
    pub hh: Vec<f64>,
    pub lh: Vec<f64>,
    pub hl: Vec<f64>,
    pub ll: Vec<f64>,
    pub bullish_bos: Vec<f64>,
    pub bullish_choch: Vec<f64>,
    pub bearish_bos: Vec<f64>,
    pub bearish_choch: Vec<f64>,
}

The stream output exposes the same 16 fields as scalars, and batch output exposes the same 16 fields as flattened row-major matrices plus combos, rows, and cols.

Validation, Warmup & NaNs
  • Input requires matching high, low, and close lengths.
  • Empty input returns EmptyInputData; all-NaN input returns AllValuesNaN.
  • Minimum valid history is the maximum of swing_size * 2 + 1, basis_length, and atr_length + atr_smooth - 1.
  • Single-run warmup prefix is first_valid + max(swing_size * 2, basis_length - 1, atr_length + atr_smooth - 2).
  • Before the basis and smoothed ATR are both ready, stream updates return None.
  • Output arrays are length-checked for all 16 destination slices in market_structure_confluence_into_slices.
  • Batch APIs require a batch kernel; non-batch kernels return InvalidKernelForBatch.
Error Handling
use vector_ta::indicators::market_structure_confluence::{
    market_structure_confluence,
    MarketStructureConfluenceError,
};

match market_structure_confluence(&input) {
    Ok(output) => println!("Computed {} bars", output.basis.len()),
    Err(MarketStructureConfluenceError::DataLengthMismatch { high, low, close }) =>
        eprintln!("Length mismatch: high={}, low={}, close={}", high, low, close),
    Err(MarketStructureConfluenceError::InvalidBosConfirmation { bos_confirmation }) =>
        eprintln!("Invalid BOS confirmation: {}", bos_confirmation),
    Err(MarketStructureConfluenceError::NotEnoughValidData { needed, valid }) =>
        eprintln!("Need {} valid bars, found {}", needed, valid),
    Err(e) => eprintln!("Market Structure Confluence error: {}", e),
}

Python Bindings

Basic Usage

The Python function returns a dict keyed by every output field:

import numpy as np
from vector_ta import market_structure_confluence

result = market_structure_confluence(
    high=np.asarray(high, dtype=np.float64),
    low=np.asarray(low, dtype=np.float64),
    close=np.asarray(close, dtype=np.float64),
    swing_size=10,
    bos_confirmation="Candle Close",
    basis_length=100,
    atr_length=14,
    atr_smooth=21,
    vol_mult=2.0,
    kernel="auto",
)

direction = result["structure_direction"]
bullish_bos = result["bullish_bos"]
upper_band = result["upper_band"]
Streaming Real-time Updates

The Python stream class returns a 16-value list in fixed field order:

from vector_ta import MarketStructureConfluenceStream

stream = MarketStructureConfluenceStream(
    swing_size=10,
    bos_confirmation="Candle Close",
    basis_length=100,
    atr_length=14,
    atr_smooth=21,
    vol_mult=2.0,
)

for h, l, c in bars:
    point = stream.update(h, l, c)
    if point is not None:
        basis, upper_band, lower_band, structure_direction, bullish_arrow, bearish_arrow, bullish_change, bearish_change, hh, lh, hl, ll, bullish_bos, bullish_choch, bearish_bos, bearish_choch = point
Batch Processing

Batch output returns every matrix plus parameter metadata arrays:

import numpy as np
from vector_ta import market_structure_confluence_batch

result = market_structure_confluence_batch(
    high=np.asarray(high, dtype=np.float64),
    low=np.asarray(low, dtype=np.float64),
    close=np.asarray(close, dtype=np.float64),
    swing_size_range=(8, 12, 2),
    bos_confirmation_options=["Candle Close", "Wicks"],
    basis_length_range=(80, 100, 20),
    atr_length_range=(14, 14, 0),
    atr_smooth_range=(21, 21, 0),
    vol_mult_range=(2.0, 3.0, 1.0),
    kernel="auto",
)

basis = result["basis"]
bearish_choch = result["bearish_choch"]
swing_sizes = result["swing_sizes"]
bos_confirmations = result["bos_confirmations"]
rows = result["rows"]
cols = result["cols"]

JavaScript/WASM Bindings

Basic Usage

The primary WASM binding returns an object with the same 16 output fields:

import { market_structure_confluence_js } from 'vectorta-wasm';

const result = market_structure_confluence_js(
  new Float64Array(high),
  new Float64Array(low),
  new Float64Array(close),
  10,
  "Candle Close",
  100,
  14,
  21,
  2.0
);

console.log(result.structure_direction);
console.log(result.bullish_bos);
Batch Processing

The batch export name is market_structure_confluence_batch and it returns all series plus parameter arrays:

import { market_structure_confluence_batch } from 'vectorta-wasm';

const result = market_structure_confluence_batch(
  new Float64Array(high),
  new Float64Array(low),
  new Float64Array(close),
  {
    swing_size_range: [8, 12, 2],
    bos_confirmation_options: ["Candle Close", "Wicks"],
    basis_length_range: [80, 100, 20],
    atr_length_range: [14, 14, 0],
    atr_smooth_range: [21, 21, 0],
    vol_mult_range: [2.0, 3.0, 1.0],
  }
);

console.log(result.rows, result.cols);
console.log(result.basis);
console.log(result.swing_sizes);
console.log(result.bos_confirmations);
Low-level WASM Notes

This Rust reference exports object-returning WASM functions for single and batch usage. It does not expose the separate alloc, free, or pointer-based into helpers that some other indicators provide.

CUDA Bindings (Rust)

Additional details for the CUDA bindings can be found inside the VectorTA repository.

Performance Analysis

Comparison:
View:
Placeholder data (no recorded benchmarks for this indicator)

Across sizes, Rust CPU runs about 1.14× faster than Tulip C in this benchmark.

Loading chart...

AMD Ryzen 9 9950X (CPU) | NVIDIA RTX 4090 (GPU)

Related Indicators