What are Murrey Math Lines?
Murrey Math Lines are a system of geometric price lines derived from the principles of W.D. Gann's squares. Developed by T. H. Murrey, this indicator simplifies Gann's complex theories into a practical set of equally spaced horizontal lines that divide price action into eight "octaves" or zones. These lines are intended to represent major and minor support and resistance levels where price is likely to find equilibrium, reverse, or accelerate.
The core idea behind Murrey Math is that price tends to move in predictable ranges and will often react strongly at specific, harmonically related levels. Each of the nine lines (from 0/8 to 8/8) has a specific interpretation regarding price behavior:
- 0/8 (Extreme Oversold) & 8/8 (Extreme Overbought): Strong support/resistance, indicating extreme conditions. Price rarely stays here long.
- 1/8 (Weak Support) & 7/8 (Weak Resistance): Reversal zones. Price often reverses quickly from these levels.
- 2/8 (Strong Support) & 6/8 (Strong Resistance): These are strong pivot points where price is likely to pause or reverse.
- 3/8 (Minor Support) & 5/8 (Minor Resistance): Trading ranges often occur between these lines. Price may try to reverse from here, but less strongly than from 2/8 or 6/8.
- 4/8 (Major Reversal/Median Line): The strongest support/resistance level. Price tends to gravitate towards this line, often reversing direction after crossing it.
In Pine Script, implementing Murrey Math Lines involves defining a major price range (a "square") and then calculating these octave levels dynamically. They are a powerful tool for visual traders and can inform your pine script strategies for entries, exits, and understanding market structure.
Components and Calculation
The calculation of Murrey Math Lines begins by identifying a significant trading range, often called the "Major Square." This range's highest high and lowest low within a defined period (e.g., 64, 128, or 256 bars) forms the basis. The range is then divided into eight equal parts.
Let `HH` be the Highest High and `LL` be the Lowest Low over a specified `period`.
- Determine the Major Square Range: * Find the `Max_Price = ta.highest(high, period)` * Find the `Min_Price = ta.lowest(low, period)` * `Price_Range = Max_Price - Min_Price`
- Adjust Price Range to Nearest Power of 2 (for proper scaling): Murrey's method involves scaling the price range to a power of 2 (e.g., 1, 2, 4, 8, 16, 32, 64, 128, etc.) to fit it within a "square." This normalization helps maintain consistency across different assets and price scales. * `Scaled_Range = (math.pow(2, math.ceil(math.log(Price_Range) / math.log(2))))` * `Min_Price_Adjusted = Min_Price - (Scaled_Range - Price_Range) / 2` * `Max_Price_Adjusted = Min_Price_Adjusted + Scaled_Range`
- Calculate the Octave Step: * `Octave_Step = Scaled_Range / 8`
- Calculate Each Murrey Math Line: * `0/8 Line = Min_Price_Adjusted` * `1/8 Line = Min_Price_Adjusted + Octave_Step` * `2/8 Line = Min_Price_Adjusted + (2 * Octave_Step)` * `3/8 Line = Min_Price_Adjusted + (3 * Octave_Step)` * `4/8 Line = Min_Price_Adjusted + (4 * Octave_Step)` (Median Line) * `5/8 Line = Min_Price_Adjusted + (5 * Octave_Step)` * `6/8 Line = Min_Price_Adjusted + (6 * Octave_Step)` * `7/8 Line = Min_Price_Adjusted + (7 * Octave_Step)` * `8/8 Line = Max_Price_Adjusted`
These lines will remain constant for the period defined by the `lookbackPeriod` input until a new highest high or lowest low is established, forcing a recalculation of the "Major Square."
Basic Murrey Math Lines Implementation in Pine Script
Since Pine Script does not have a built-in `ta.murreyMathLines()` function, we will implement the calculation logic directly using standard Pine Script functions.
//@version=5
indicator("My Murrey Math Lines", overlay=true, max_bars_back=500) // overlay=true to plot on price chart.
// --- User Inputs ---
// Period for identifying the major square (highest high and lowest low)
lookbackPeriod = input.int(256, title="Lookback Period (Bars for Major Square)", minval=64, maxval=500)
lineTransparency = input.int(0, title="Line Transparency (0-100)", minval=0, maxval=100)
showLabels = input.bool(true, title="Show Level Labels")
// --- Calculate Murrey Math Levels ---
// 1. Find Highest High and Lowest Low over the lookback period
highestHigh = ta.highest(high, lookbackPeriod)
lowestLow = ta.lowest(low, lookbackPeriod)
// We only recalculate the base prices if a new significant high or low occurs.
// This makes the lines stable for periods and then shift.
var float mmHighest = na
var float mmLowest = na
var float mmRange = na
// Recalculate MM base levels when a new highest high or lowest low is found within the lookback
// Use `ta.highestbars` and `ta.lowestbars` to find if the current high/low is the period's extreme
if (high[0] == highestHigh and bar_index == bar_index[ta.highestbars(high, lookbackPeriod)]) or
(low[0] == lowestLow and bar_index == bar_index[ta.lowestbars(low, lookbackPeriod)])
// 2. Adjust Price Range to Nearest Power of 2 (for proper scaling)
priceRange = highestHigh - lowestLow
// Handle cases where priceRange might be zero or too small
if priceRange == 0
priceRange := 0.000000001 // Small non-zero value to prevent issues
// Calculate the power of 2 that covers the price range
pow2 = math.ceil(math.log(priceRange) / math.log(2))
scaledRange = math.pow(2, pow2)
// Adjust the lowest price so that the range fits perfectly within the scaledRange
adjustedLowest = lowestLow - (scaledRange - priceRange) / 2
// Store these values to use for plotting all subsequent bars until a new extreme
mmHighest := adjustedLowest + scaledRange
mmLowest := adjustedLowest
mmRange := scaledRange
// Use `nz()` to carry forward the last calculated levels
mmHighest := nz(mmHighest[1], mmHighest)
mmLowest := nz(mmLowest[1], mmLowest)
mmRange := nz(mmRange[1], mmRange)
// 3. Calculate the Octave Step
octaveStep = mmRange / 8.0
// 4. Calculate Each Murrey Math Line
mm_8_8 = mmHighest
mm_7_8 = mmHighest - octaveStep
mm_6_8 = mmHighest - (2 * octaveStep)
mm_5_8 = mmHighest - (3 * octaveStep)
mm_4_8 = mmHighest - (4 * octaveStep) // Median Line
mm_3_8 = mmLowest + (3 * octaveStep)
mm_2_8 = mmLowest + (2 * octaveStep)
mm_1_8 = mmLowest + octaveStep
mm_0_8 = mmLowest
// --- Plotting Murrey Math Levels ---
// Define colors and styles for each line for easier interpretation
color_8_0 = color.new(color.red, lineTransparency)
color_7_1 = color.new(color.orange, lineTransparency)
color_6_2 = color.new(color.maroon, lineTransparency) // Stronger resistance/support
color_5_3 = color.new(color.gray, lineTransparency)
color_4_4 = color.new(color.purple, lineTransparency) // Median line, strongest
color_line = color.new(color.blue, lineTransparency)
plot(mm_0_8, title="0/8", color=color_8_0, linewidth=1, style=plot.style_stepline)
plot(mm_1_8, title="1/8", color=color_7_1, linewidth=1, style=plot.style_stepline)
plot(mm_2_8, title="2/8", color=color_6_2, linewidth=2, style=plot.style_stepline) // Stronger
plot(mm_3_8, title="3/8", color=color_5_3, linewidth=1, style=plot.style_stepline)
plot(mm_4_8, title="4/8", color=color_4_4, linewidth=3, style=plot.style_stepline) // Strongest
plot(mm_5_8, title="5/8", color=color_5_3, linewidth=1, style=plot.style_stepline)
plot(mm_6_8, title="6/8", color=color_6_2, linewidth=2, style=plot.style_stepline) // Stronger
plot(mm_7_8, title="7/8", color=color_7_1, linewidth=1, style=plot.style_stepline)
plot(mm_8_8, title="8/8", color=color_8_0, linewidth=1, style=plot.style_stepline)
// --- Optional: Add Labels to Lines ---
if showLabels and bar_index == last_bar_index
// Only draw labels on the current (last) bar for clarity
label.new(x=bar_index, y=mm_0_8, text="0/8 - Extreme Oversold", style=label.style_label_left, color=color_8_0, textcolor=color.white, size=size.small)
label.new(x=bar_index, y=mm_1_8, text="1/8 - Weak Support", style=label.style_label_left, color=color_7_1, textcolor=color.white, size=size.small)
label.new(x=bar_index, y=mm_2_8, text="2/8 - Strong Support", style=label.style_label_left, color=color_6_2, textcolor=color.white, size=size.small)
label.new(x=bar_index, y=mm_3_8, text="3/8 - Minor Support", style=label.style_label_left, color=color_5_3, textcolor=color.white, size=size.small)
label.new(x=bar_index, y=mm_4_8, text="4/8 - Median Line (Major S/R)", style=label.style_label_left, color=color_4_4, textcolor=color.white, size=size.small)
label.new(x=bar_index, y=mm_5_8, text="5/8 - Minor Resistance", style=label.style_label_left, color=color_5_3, textcolor=color.white, size=size.small)
label.new(x=bar_index, y=mm_6_8, text="6/8 - Strong Resistance", style=label.style_label_left, color=color_6_2, textcolor=color.white, size=size.small)
label.new(x=bar_index, y=mm_7_8, text="7/8 - Weak Resistance", style=label.style_label_left, color=color_7_1, textcolor=color.white, size=size.small)
label.new(x=bar_index, y=mm_8_8, text="8/8 - Extreme Overbought", style=label.style_label_left, color=color_8_0, textcolor=color.white, size=size.small)
// --- Simple Strategy Example (Conceptual) ---
// This strategy demonstrates how you might react to Murrey Math levels.
// It is highly simplified and for educational purposes only.
// Real trading strategies require more complex confirmation.
strategy("Murrey Math Strategy", overlay=true)
// Use the calculated Murrey Math levels for strategy logic
// Re-calculate the levels to ensure they are available to the strategy
// (This is redundant if the above indicator part is run first, but good practice for standalone strategy)
var float strat_mmHighest = na
var float strat_mmLowest = na
var float strat_mmRange = na
highestHigh_strat = ta.highest(high, lookbackPeriod)
lowestLow_strat = ta.lowest(low, lookbackPeriod)
if (high[0] == highestHigh_strat and bar_index == bar_index[ta.highestbars(high, lookbackPeriod)]) or
(low[0] == lowestLow_strat and bar_index == bar_index[ta.lowestbars(low, lookbackPeriod)])
priceRange_strat = highestHigh_strat - lowestLow_strat
if priceRange_strat == 0
priceRange_strat := 0.000000001
pow2_strat = math.ceil(math.log(priceRange_strat) / math.log(2))
scaledRange_strat = math.pow(2, pow2_strat)
adjustedLowest_strat = lowestLow_strat - (scaledRange_strat - priceRange_strat) / 2
strat_mmHighest := adjustedLowest_strat + scaledRange_strat
strat_mmLowest := adjustedLowest_strat
strat_mmRange := scaledRange_strat
strat_mmHighest := nz(strat_mmHighest[1], strat_mmHighest)
strat_mmLowest := nz(strat_mmLowest[1], strat_mmLowest)
strat_mmRange := nz(strat_mmRange[1], strat_mmRange)
strat_octaveStep = strat_mmRange / 8.0
strat_mm_0_8 = strat_mmLowest
strat_mm_1_8 = strat_mmLowest + strat_octaveStep
strat_mm_2_8 = strat_mmLowest + (2 * strat_octaveStep)
strat_mm_3_8 = strat_mmLowest + (3 * strat_octaveStep)
strat_mm_4_8 = strat_mmLowest + (4 * strat_octaveStep)
strat_mm_5_8 = strat_mmLowest + (5 * strat_octaveStep)
strat_mm_6_8 = strat_mmLowest + (6 * strat_octaveStep)
strat_mm_7_8 = strat_mmLowest + (7 * strat_octaveStep)
strat_mm_8_8 = strat_mmHighest
// Strategy Logic: Reversals at 0/8, 8/8, and 4/8 lines (Median Line)
// Buy at 0/8 or 1/8 (extreme oversold/weak support)
longCondition = ta.crossover(close, strat_mm_0_8) or ta.crossover(close, strat_mm_1_8)
// Sell at 8/8 or 7/8 (extreme overbought/weak resistance)
shortCondition = ta.crossunder(close, strat_mm_8_8) or ta.crossunder(close, strat_mm_7_8)
// Additional reversal at 4/8 (Median Line) - can be entry or exit
// If price crosses 4/8 from below, it's bullish. If from above, it's bearish.
long4_8 = ta.crossover(close, strat_mm_4_8)
short4_8 = ta.crossunder(close, strat_mm_4_8)
if (longCondition)
strategy.entry("Long MM", strategy.long)
if (shortCondition)
strategy.entry("Short MM", strategy.short)
// Exit logic: Using 4/8 line as profit target or reversal point
// Or using fixed stop loss and profit target based on levels
profitTargetLong = strat_mm_4_8 // Target 4/8 for long
stopLossLong = strat_mm_0_8 - (strat_octaveStep / 2) // Below 0/8, giving some buffer
profitTargetShort = strat_mm_4_8 // Target 4/8 for short
stopLossShort = strat_mm_8_8 + (strat_octaveStep / 2) // Above 8/8, giving some buffer
strategy.exit("Long MM Exit", from_entry="Long MM", profit=profitTargetLong, stop=stopLossLong)
strategy.exit("Short MM Exit", from_entry="Short MM", profit=profitTargetShort, stop=stopLossShort)
Optimizing Murrey Math Lines Performance
To get the most from Murrey Math Lines in Pine Script:
- Lookback Period Tuning: The `lookbackPeriod` is critical. A longer period (e.g., 256 bars) creates broader, more stable levels, suitable for higher timeframes and long-term analysis. Shorter periods (e.g., 64 bars) create more dynamic levels suitable for short-term trading. Experiment to find the optimal period for your asset and timeframe.
- Confluence is Key: Murrey Math Lines are most effective when they align with other forms of support/resistance, such as:
- Trendlines
- Moving Averages
- Previous significant highs/lows
- Fibonacci Retracements
- Price Action Confirmation: Always confirm price reactions at Murrey Math levels with strong candlestick patterns (e.g., bullish engulfing, hammer at support; bearish engulfing, shooting star at resistance) and volume.
- Understanding Line Behavior: Learn the specific characteristics of each octave (e.g., price bouncing quickly from 1/8 and 7/8, strong reactions at 2/8 and 6/8, the magnet effect of 4/8).
- Trade Management: Use the lines for entry, target, and stop-loss placement. For example, enter a long trade at 2/8 with a target at 4/8 and a stop-loss just below 1/8.
- Adapting to Volatility: In highly volatile markets, the "Octave Step" will be larger, creating wider zones. In low-volatility markets, they will be tighter. Adjust your expectations accordingly.
Common Murrey Math Lines Pitfalls
- Subjectivity of "Major Square": While the calculation is fixed, defining the `lookbackPeriod` for the initial highest high and lowest low can be subjective. An improperly chosen period can lead to irrelevant lines.
- Not Always Exact: While often precise, price will not always bounce exactly off a Murrey Math line. They should be treated as zones or areas of interest.
- Complex Calculation: The underlying mathematical adjustments (to a power of 2) can be challenging to understand for beginners, making it feel less intuitive than simple moving averages.
- Whipsaws in Choppy Markets: In highly consolidating or whipsaw markets, price might oscillate frequently between levels, generating false signals if not combined with other filters.
- Over-Reliance: Like all indicators, Murrey Math Lines are best used as part of a comprehensive trading plan, not as a standalone signal generator.
- Lagging Element: While the lines themselves are fixed for a period, the initial determination of the "Major Square" is based on past price action, introducing a slight lagging element for the overall framework.
Conclusion
Murrey Math Lines offer a fascinating and structured approach to technical analysis in Pine Script for TradingView. Derived from W.D. Gann's theories, these equally spaced horizontal lines provide a unique framework for identifying potential support, resistance, and crucial turning points within various "octaves" of price action. While their calculation requires a clear definition of the "Major Square" and their interpretation benefits from an understanding of each line's significance, mastering Murrey Math can significantly enhance your pine script strategies. By combining these powerful levels with price action confirmation, volume analysis, and other technical tools, you can leverage Murrey Math Lines to improve your decision-making, anticipate market reactions, and gain a deeper understanding of market harmony and equilibrium.