Market Structure Break (MSB) Detector

A custom indicator created by TrendSpider Team on TrendSpider. You can import this script into your TrendSpider account. Don't have TrendSpider? Create an account first, then import the script.

Chart featuring the Market Structure Break (MSB) Detector indicator

This indicator detects market structure breaks (MSBs) by identifying key swing highs and swing lows and marking when price closes above a swing high (bullish MSB) or below a swing low (bearish MSB).

Swing High: A high with two lower highs on either side.

Swing Low: A low with two higher lows on either side.

Features:

✅ MSB Labels & Lines – Marks MSBs with a label and a horizontal line extending from the broken swing level.

✅ Color Coding – Green for bullish MSBs, red for bearish MSBs.

✅ Customizable Line Style – Adjust line thickness, color, dash pattern, and length (default: 50 bars).

✅ Smart Line Expiration – Prevents old MSB lines from extending indefinitely to reduce clutter.

This indicator helps traders visualize shifts in market structure and identify key breakout levels with precision. 🚀

Source code

This indicator had been implemented by TrendSpider Team in JavaScript on TrendSpider. Check out the developer documentation to learn more about JS on TrendSpider.

describe_indicator('Market Structure Break (MSB) Detector');

// Input parameters for customization
const swingLookback = input.number('Swing Lookback', 3, { min: 2 });
const bullishColor = input.color('Bullish MSB Color', '#00FF00');
const bearishColor = input.color('Bearish MSB Color', '#FF0000');
const lineLength = input.number('MSB Line Length (bars)', 20, { min: 10, max: 200 });
const msbLookback = input.number('MSB Lookback Period', 100, { min: 1, max: 1000 });

// Function to detect swing highs and lows
const detectSwings = (high, low, lookback) => {
    const swingHighs = series_of(null);
    const swingLows = series_of(null);
    for (let i = lookback; i < high.length - lookback; i++) {
        let isSwingHigh = true;
        let isSwingLow = true;
        for (let j = 1; j <= lookback; j++) {
            if (high[i - j] >= high[i] || high[i + j] >= high[i]) {
                isSwingHigh = false;
            }
            if (low[i - j] <= low[i] || low[i + j] <= low[i]) {
                isSwingLow = false;
            }
        }
        if (isSwingHigh) {
            swingHighs[i] = high[i];
        }
        if (isSwingLow) {
            swingLows[i] = low[i];
        }
    }
    return { swingHighs, swingLows };
};

// Detect swings
const { swingHighs, swingLows } = detectSwings(high, low, swingLookback);

// Detect Market Structure Breaks
const bullishMSB = series_of(null);
const bearishMSB = series_of(null);
const bullishMSBLines = [];
const bearishMSBLines = [];
let lastSwingHighIndex = null;
let lastSwingLowIndex = null;

for (let i = swingLookback; i < close.length; i++) {
    if (swingHighs[i] !== null) {
        lastSwingHighIndex = i;
    }
    if (swingLows[i] !== null) {
        lastSwingLowIndex = i;
    }
    
    if (lastSwingHighIndex !== null && close[i] > high[lastSwingHighIndex]) {
        bullishMSB[i] = high[lastSwingHighIndex];
        bullishMSBLines.push({
            startIndex: lastSwingHighIndex,
            breakIndex: i,
            value: high[lastSwingHighIndex]
        });
        lastSwingHighIndex = null;
    }
    
    if (lastSwingLowIndex !== null && close[i] < low[lastSwingLowIndex]) {
        bearishMSB[i] = low[lastSwingLowIndex];
        bearishMSBLines.push({
            startIndex: lastSwingLowIndex,
            breakIndex: i,
            value: low[lastSwingLowIndex]
        });
        lastSwingLowIndex = null;
    }
}

// Function to create a line
const createLine = (startIndex, breakIndex, value, color, isBullish, lineIndex) => {
    const lineData = series_of(null);
    const endIndex = Math.min(breakIndex + lineLength, close.length);
    for (let i = startIndex; i < endIndex; i++) {
        lineData[i] = value;
    }
    const paintedLine = paint(lineData, {
        color: color,
        name: `${isBullish ? 'Bullish' : 'Bearish'} MSB ${lineIndex}`
    });
    
    // Place label at the swing high/low candle
    const labelIndex = isBullish ? startIndex : startIndex;
    paint_label_at_line(paintedLine, labelIndex, 'MSB', {
        color: color,
        vertical_align: isBullish ? 'top' : 'bottom'
    });
};

// Paint MSB lines and labels
const currentIndex = close.length - 1;
const msbLookbackStartIndex = Math.max(0, currentIndex - msbLookback);
bullishMSBLines.filter(line => line.breakIndex >= msbLookbackStartIndex).forEach((line, index) => {
    createLine(line.startIndex, line.breakIndex, line.value, bullishColor, true, index);
});
bearishMSBLines.filter(line => line.breakIndex >= msbLookbackStartIndex).forEach((line, index) => {
    createLine(line.startIndex, line.breakIndex, line.value, bearishColor, false, index);
});