# IPM Liquidity Divergence (Main) | LIQ





declare lower;

# ——————————————————————
# INPUTS
# ——————————————————————
input fastLength = 5;
input smoothLength = 5;
input lookbackBars = 5;
input signalThreshold = 5.0;

input showPressureLine = yes;
input showZeroLine = yes;
input showSignalBalls = yes;

# ——————————————————————
# PRICE + PRESSURE
# ——————————————————————
def barRange = Max(high - low, TickSize());
def closePos = if barRange != 0 then (close - low) / barRange else 0.5;

def buyPressureRaw = volume * closePos;
def sellPressureRaw = volume * (1 - closePos);

def buyPressure = ExpAverage(buyPressureRaw, fastLength);
def sellPressure = ExpAverage(sellPressureRaw, fastLength);

def pressureTotal = buyPressure + sellPressure;
def pressureDelta = buyPressure - sellPressure;

def imbalancePct = if pressureTotal != 0 then 100.0 * pressureDelta / pressureTotal else 0.0;
def imbalanceSm = ExpAverage(imbalancePct, smoothLength);

# ——————————————————————
# DIVERGENCE LOGIC
# ——————————————————————
def priceNearLow = low <= Lowest(low, lookbackBars);
def priceNearHigh = high >= Highest(high, lookbackBars);

def bullDivRaw = priceNearLow and imbalanceSm > imbalanceSm[1] and imbalanceSm < 0 and AbsValue(imbalanceSm) >= signalThreshold;
def bearDivRaw = priceNearHigh and imbalanceSm < imbalanceSm[1] and imbalanceSm > 0 and AbsValue(imbalanceSm) >= signalThreshold;

# ——————————————————————
# LOCKOUT STATE LOGIC (Recursive Memory)
# ——————————————————————
def bullLock = if bullDivRaw == 0 then 0 else if bullDivRaw == 1 and bullLock[1] == 0 then 1 else bullLock[1];
def bearLock = if bearDivRaw == 0 then 0 else if bearDivRaw == 1 and bearLock[1] == 0 then 1 else bearLock[1];

def bullSignal = bullDivRaw and bullLock[1] == 0;
def bearSignal = bearDivRaw and bearLock[1] == 0;

# ——————————————————————
# PLOTS
# ——————————————————————
plot ZeroLine = if showZeroLine then 0 else Double.NaN;
ZeroLine.SetDefaultColor(Color.GRAY);

plot LiquidityPressure = if showPressureLine then imbalanceSm else Double.NaN;
LiquidityPressure.AssignValueColor(if imbalanceSm >= 0 then Color.CYAN else Color.MAGENTA);
LiquidityPressure.SetLineWeight(2);

plot BullishDiv = if showSignalBalls and bullSignal then imbalanceSm else Double.NaN;
BullishDiv.SetPaintingStrategy(PaintingStrategy.POINTS);
BullishDiv.SetDefaultColor(Color.GREEN);
BullishDiv.SetLineWeight(3);

plot BearishDiv = if showSignalBalls and bearSignal then imbalanceSm else Double.NaN;
BearishDiv.SetPaintingStrategy(PaintingStrategy.POINTS);
BearishDiv.SetDefaultColor(Color.RED);
BearishDiv.SetLineWeight(3);

# ——————————————————————
# ALERTS
# ——————————————————————
Alert(bullSignal, "IPM Bullish Liquidity Divergence", Alert.BAR, Sound.Bell);
Alert(bearSignal, "IPM Bearish Liquidity Divergence", Alert.BAR, Sound.Ring);