Gravity Trend Levels [BOSWaves]
Acceleration-Derived Gravity Modeling with Adaptive Cloud Trail and Fail Level Projection
Original code: https://www.tradingview.com/script/nCUyWa7D-Gravity-Trend-Levels-BOSWaves/
Overview
Gravity Trend Levels [BOSWaves] is a momentum acceleration-based trend system that models directional gravity through the normalized rate of change of an EMA-derived velocity measurement, where cloud thickness, trail distance, and trend state are continuously adapted based on whether gravitational pull is building, sustained, or decaying rather than through fixed volatility multipliers or static band thresholds.
I enhanced this indicator to include two bands. MAD and ATR Extensions. When the MAD bands are inside the ATR bands, then it indicates a SQUEEZE condition. This is indicated with white overlays shown below. When price is in this condition, expect a large move. All of the bands are on/off selectable in the inputs.
Acceleration-Derived Gravity Modeling with Adaptive Cloud Trail and Fail Level Projection
Original code: https://www.tradingview.com/script/nCUyWa7D-Gravity-Trend-Levels-BOSWaves/
Overview
Gravity Trend Levels [BOSWaves] is a momentum acceleration-based trend system that models directional gravity through the normalized rate of change of an EMA-derived velocity measurement, where cloud thickness, trail distance, and trend state are continuously adapted based on whether gravitational pull is building, sustained, or decaying rather than through fixed volatility multipliers or static band thresholds.
I enhanced this indicator to include two bands. MAD and ATR Extensions. When the MAD bands are inside the ATR bands, then it indicates a SQUEEZE condition. This is indicated with white overlays shown below. When price is in this condition, expect a large move. All of the bands are on/off selectable in the inputs.
Code:
# ============================================================
# ============================================================
# Gravity Trend Levels [BOSWaves]
# Original Pine Script © BOSWaves https://www.tradingview.com/script/nCUyWa7D-Gravity-Trend-Levels-BOSWaves/
# Converted by Chewie 6/2/2026
# Target Bands added
# ============================================================
declare upper;
# ─────────────────────────────────────────────────────────────
# INPUTS
# ─────────────────────────────────────────────────────────────
input alert = yes;
input len = 14; # Trend Length — higher = smoother, fewer flips
input gravLen = 19; # Gravity Lookback — lower = more reactive
input decayRate = 0.96; # Gravity Decay — higher = gravity lingers longer
input madLen = 24; # MAD Length — higher = smoother trail
input trailMin = 1.0; # Trail Min (Strong Pull)
input trailMax = 1.0; # Trail Max (Weak Pull)
input showCloud = yes; # Show Gravity Cloud
input paintBars = no; # Color Bars
input showSignals = yes; # Show Buy/Sell Signals
input showLevels = yes; # Show Gravity Fail Levels
input levelLen = 50; # Level Projection Length (bars forward)
input showDots = yes; # Retest Diamonds
input dotCooldown = 12; # Retest Cooldown (min bars between diamonds)
input signalBuffer = 10; # Signal Buffer Period (bars after flip before diamonds)
# ─────────────────────────────────────────────────────────────
# TARGET BAND INPUTS
# ─────────────────────────────────────────────────────────────
input showMADBands = yes; # Show MAD Extension Bands
input madMult1 = 2.0; # MAD Moderate Extension
input madMult2 = 3.0; # MAD Extreme Extension
input showATRBands = yes; # Show ATR Extension Bands
input atrLen = 14; # ATR Length
input atrMult1 = 1.5; # ATR Moderate Extension
input atrMult2 = 2.5; # ATR Extreme Extension
# ─────────────────────────────────────────────────────────────
# COLORS
# ─────────────────────────────────────────────────────────────
DefineGlobalColor("Bull", Color.GREEN);
DefineGlobalColor("Bear", Color.RED);
# ─────────────────────────────────────────────────────────────
# CORE — Basis & Volatility (MAD)
# ─────────────────────────────────────────────────────────────
def basis = ExpAverage(close, len);
def meanC = Average(close, madLen);
def mad = Average(AbsValue(close - meanC), madLen);
# ─────────────────────────────────────────────────────────────
# GRAVITY DETECTION
# ─────────────────────────────────────────────────────────────
def velocity = basis - basis[gravLen];
def accelRaw = velocity - velocity[1];
def normAccel = if mad > 0 then AbsValue(accelRaw) / mad else 0.0;
def gravity;
if normAccel > 0.01 {
gravity = Min(normAccel * 8.0, 2.0);
} else {
gravity = gravity[1] * decayRate;
}
def pull = Min(gravity / 1.5, 1.0);
# ─────────────────────────────────────────────────────────────
# ADAPTIVE TRAIL BANDS
# ─────────────────────────────────────────────────────────────
def trailMult = trailMax - (trailMax - trailMin) * pull;
def upper_band = basis + mad * trailMult;
def lower_band = basis - mad * trailMult;
# ─────────────────────────────────────────────────────────────
# SIGNAL / TREND LOGIC
# ─────────────────────────────────────────────────────────────
def longCond = close crosses above upper_band;
def shortCond = close crosses below lower_band;
def lastSignal;
if longCond {
lastSignal = 1;
} else if shortCond {
lastSignal = -1;
} else {
lastSignal = lastSignal[1];
}
def switchUp = lastSignal == 1 and lastSignal[1] == -1;
def switchDown = lastSignal == -1 and lastSignal[1] == 1;
def lastSignalBar;
if switchUp or switchDown {
lastSignalBar = BarNumber();
} else {
lastSignalBar = lastSignalBar[1];
}
# ─────────────────────────────────────────────────────────────
# GRAVITY CLOUD
# ─────────────────────────────────────────────────────────────
def cloudThick = mad * (0.3 + 0.5 * pull);
def cloudOuter = if lastSignal == 1 then lower_band else upper_band;
def cloudInner = if lastSignal == 1 then lower_band + cloudThick else upper_band - cloudThick;
def cloudOuterVis = ExpAverage(cloudOuter, 5);
def cloudInnerVis = ExpAverage(cloudInner, 5);
plot CloudOuterPlot = if showCloud then cloudOuterVis else Double.NaN;
CloudOuterPlot.SetLineWeight(2);
CloudOuterPlot.AssignValueColor(if lastSignal == 1 then GlobalColor("Bull") else GlobalColor("Bear"));
CloudOuterPlot.SetPaintingStrategy(PaintingStrategy.LINE);
plot CloudInnerPlot = if showCloud then cloudInnerVis else Double.NaN;
CloudInnerPlot.SetLineWeight(1);
CloudInnerPlot.AssignValueColor(if lastSignal == 1
then CreateColor(0, 200, 0)
else CreateColor(200, 0, 0));
CloudInnerPlot.SetPaintingStrategy(PaintingStrategy.LINE);
AddCloud(CloudOuterPlot, CloudInnerPlot,
Color.MAGENTA, Color.CYAN);
# ─────────────────────────────────────────────────────────────
# BAR COLORING
# ─────────────────────────────────────────────────────────────
AssignPriceColor(
if !paintBars then Color.CURRENT
else if lastSignal == 1 then GlobalColor("Bull")
else GlobalColor("Bear")
);
# ─────────────────────────────────────────────────────────────
# BUY / SELL SIGNALS
# ─────────────────────────────────────────────────────────────
plot BuySignal = if showSignals and switchUp then low - mad * 1.5 else Double.NaN;
BuySignal.SetPaintingStrategy(PaintingStrategy.ARROW_UP);
BuySignal.SetDefaultColor(GlobalColor("Bull"));
BuySignal.SetLineWeight(3);
BuySignal.Hide();
AddChartBubble(showSignals and switchUp,
low - mad * 1.5,
"B",
GlobalColor("Bull"),
no);
AddChartBubble(showSignals and switchDown,
high + mad * 1.5,
"S",
GlobalColor("Bear"),
yes);
# ─────────────────────────────────────────────────────────────
# GRAVITY FAIL LEVELS
# ─────────────────────────────────────────────────────────────
def flipBullPrice = if switchUp then low else Double.NaN;
def flipBearPrice = if switchDown then high else Double.NaN;
def barsAfterBullFlip;
if switchUp {
barsAfterBullFlip = 0;
} else if barsAfterBullFlip[1] < levelLen {
barsAfterBullFlip = barsAfterBullFlip[1] + 1;
} else {
barsAfterBullFlip = levelLen + 1;
}
def carriedBullLevel;
if switchUp {
carriedBullLevel = low;
} else if barsAfterBullFlip <= levelLen {
carriedBullLevel = carriedBullLevel[1];
} else {
carriedBullLevel = Double.NaN;
}
def barsAfterBearFlip;
if switchDown {
barsAfterBearFlip = 0;
} else if barsAfterBearFlip[1] < levelLen {
barsAfterBearFlip = barsAfterBearFlip[1] + 1;
} else {
barsAfterBearFlip = levelLen + 1;
}
def carriedBearLevel;
if switchDown {
carriedBearLevel = high;
} else if barsAfterBearFlip <= levelLen {
carriedBearLevel = carriedBearLevel[1];
} else {
carriedBearLevel = Double.NaN;
}
plot BullLevel = if showLevels then carriedBullLevel else Double.NaN;
BullLevel.SetDefaultColor(CreateColor(0, 200, 0));
BullLevel.SetPaintingStrategy(PaintingStrategy.DASHES);
BullLevel.SetLineWeight(2);
BullLevel.HideBubble();
plot BearLevel = if showLevels then carriedBearLevel else Double.NaN;
BearLevel.SetDefaultColor(CreateColor(200, 0, 0));
BearLevel.SetPaintingStrategy(PaintingStrategy.DASHES);
BearLevel.SetLineWeight(2);
BearLevel.HideBubble();
# ─────────────────────────────────────────────────────────────
# RETEST DIAMONDS
# ─────────────────────────────────────────────────────────────
def farEnough = (BarNumber() - lastSignalBar) >= signalBuffer;
def bullRetest = showDots and lastSignal == 1 and low < cloudInnerVis and farEnough;
def bearRetest = showDots and lastSignal == -1 and high > cloudInnerVis and farEnough;
def lastBullDotBar;
if bullRetest and (IsNaN(lastBullDotBar[1]) or (BarNumber() - lastBullDotBar[1]) >= dotCooldown) {
lastBullDotBar = BarNumber();
} else {
lastBullDotBar = lastBullDotBar[1];
}
def lastBearDotBar;
if bearRetest and (IsNaN(lastBearDotBar[1]) or (BarNumber() - lastBearDotBar[1]) >= dotCooldown) {
lastBearDotBar = BarNumber();
} else {
lastBearDotBar = lastBearDotBar[1];
}
def bullDotOk = bullRetest and lastBullDotBar == BarNumber();
def bearDotOk = bearRetest and lastBearDotBar == BarNumber();
plot BullDot = if bullDotOk then low else Double.NaN;
BullDot.SetPaintingStrategy(PaintingStrategy.TRIANGLES);
BullDot.SetDefaultColor(GlobalColor("Bull"));
BullDot.SetLineWeight(3);
plot BearDot = if bearDotOk then high else Double.NaN;
BearDot.SetPaintingStrategy(PaintingStrategy.TRIANGLES);
BearDot.SetDefaultColor(GlobalColor("Bear"));
BearDot.SetLineWeight(3);
# ─────────────────────────────────────────────────────────────
# TARGET BANDS — MAD EXTENSIONS
# ─────────────────────────────────────────────────────────────
# Moderate zone outer edges
def madUp1 = basis + mad * madMult1;
def madDn1 = basis - mad * madMult1;
# Extreme zone outer edges
def madUp2 = basis + mad * madMult2;
def madDn2 = basis - mad * madMult2;
plot MAD_Up1 = if showMADBands then madUp1 else Double.NaN;
MAD_Up1.SetDefaultColor(CreateColor(255, 165, 0)); # orange
MAD_Up1.SetPaintingStrategy(PaintingStrategy.LINE);
MAD_Up1.SetLineWeight(1);
MAD_Up1.HideBubble();
plot MAD_Up2 = if showMADBands then madUp2 else Double.NaN;
MAD_Up2.SetDefaultColor(CreateColor(255, 80, 0)); # red-orange
MAD_Up2.SetPaintingStrategy(PaintingStrategy.LINE);
MAD_Up2.SetLineWeight(1);
MAD_Up2.HideBubble();
plot MAD_Dn1 = if showMADBands then madDn1 else Double.NaN;
MAD_Dn1.SetDefaultColor(CreateColor(0, 180, 255)); # sky blue
MAD_Dn1.SetPaintingStrategy(PaintingStrategy.LINE);
MAD_Dn1.SetLineWeight(1);
MAD_Dn1.HideBubble();
plot MAD_Dn2 = if showMADBands then madDn2 else Double.NaN;
MAD_Dn2.SetDefaultColor(CreateColor(0, 80, 255)); # deep blue
MAD_Dn2.SetPaintingStrategy(PaintingStrategy.LINE);
MAD_Dn2.SetLineWeight(1);
MAD_Dn2.HideBubble();
# Cloud fills: moderate → extreme zone (upper and lower)
AddCloud(MAD_Up2, MAD_Up1, CreateColor(255, 50, 0), CreateColor(255, 50, 0)); # red-orange upper zone
AddCloud(MAD_Dn1, MAD_Dn2, CreateColor(0, 50, 255), CreateColor(0, 50, 255)); # deep blue lower zone
# ─────────────────────────────────────────────────────────────
# TARGET BANDS — ATR EXTENSIONS
# ─────────────────────────────────────────────────────────────
def atr = Average(TrueRange(high, close, low), atrLen);
def atrUp1 = basis + atr * atrMult1;
def atrUp2 = basis + atr * atrMult2;
def atrDn1 = basis - atr * atrMult1;
def atrDn2 = basis - atr * atrMult2;
plot ATR_Up1 = if showATRBands then atrUp1 else Double.NaN;
ATR_Up1.SetDefaultColor(CreateColor(220, 220, 0)); # yellow
ATR_Up1.SetPaintingStrategy(PaintingStrategy.LINE);
ATR_Up1.SetLineWeight(1);
ATR_Up1.HideBubble();
plot ATR_Up2 = if showATRBands then atrUp2 else Double.NaN;
ATR_Up2.SetDefaultColor(CreateColor(180, 130, 0)); # dark yellow
ATR_Up2.SetPaintingStrategy(PaintingStrategy.LINE);
ATR_Up2.SetLineWeight(1);
ATR_Up2.HideBubble();
plot ATR_Dn1 = if showATRBands then atrDn1 else Double.NaN;
ATR_Dn1.SetDefaultColor(CreateColor(0, 220, 180)); # teal
ATR_Dn1.SetPaintingStrategy(PaintingStrategy.LINE);
ATR_Dn1.SetLineWeight(1);
ATR_Dn1.HideBubble();
plot ATR_Dn2 = if showATRBands then atrDn2 else Double.NaN;
ATR_Dn2.SetDefaultColor(CreateColor(0, 140, 120)); # dark teal
ATR_Dn2.SetPaintingStrategy(PaintingStrategy.LINE);
ATR_Dn2.SetLineWeight(1);
ATR_Dn2.HideBubble();
AddCloud(ATR_Up2, ATR_Up1, CreateColor(180, 130, 0), CreateColor(180, 130, 0));
AddCloud(ATR_Dn1, ATR_Dn2, CreateColor(0, 140, 120), CreateColor(0, 140, 120));
##Squeeze##
def squeezeU = if MAD_Up1 < ATR_Up1 then 1 else 0;
plot UpperEnvelope = if squeezeU is true then MAD_Up1 else Double.NaN;
UpperEnvelope.SetDefaultColor(Color.WHITE);
UpperEnvelope.SetLineWeight(4);
UpperEnvelope.HideBubble();
def squeezeD = if MAD_Dn1 > ATR_Dn1 then 1 else 0;
plot LowerEnvelope = if squeezeD is true then MAD_Dn1 else Double.NaN;
LowerEnvelope.SetDefaultColor(Color.WHITE);
LowerEnvelope.SetLineWeight(4);
LowerEnvelope.HideBubble();
# ─────────────────────────────────────────────────────────────
# ALERTS
# ─────────────────────────────────────────────────────────────
Alert(alert and switchUp, "Gravity Long — " + GetSymbol(), Alert.BAR, Sound.Ring);
Alert(alert and switchDown, "Gravity Short — " + GetSymbol(), Alert.BAR, Sound.Ring);
Alert(alert and bullDotOk or bearDotOk, "Gravity Retest — " + GetSymbol(), Alert.BAR, Sound.Ding);
Last edited: