# ===============================================================
# Fat Tony's Composite Momentum Histogram – ULTIMATE TOS VERSION
# Now with predictive status + direction labels
# ===============================================================
declare lower;
# === INPUTS (same as before) ===
input length = 14;
input fastLen = 12;
input slowLen = 26;
input sigLen = 9;
input rocLen = 10;
input stdevLen = 200;
input obLevel = 100;
input osLevel = -100;
input useVolume = yes;
input volSensitivity = 1.5;
input minVolume = 50000;
input useROC = yes;
input useTrendFilter = no;
input showDebug = no;
# === CORE CALCULATIONS (unchanged – 100% working) ===
def ema200 = ExpAverage(close, 200);
def trendUp = close > ema200;
def trendDown = close < ema200;
script tanh {
input x = 0;
def e2x = Exp(2 * x);
plot result = (e2x - 1) / (e2x + 1);
}
def hh = Highest(high, length);
def ll = Lowest(low, length);
def wpr_raw = if (hh - ll) != 0 then (hh - close) / (hh - ll) * -100 else -50;
def wr_c = wpr_raw + 50;
def k_raw = if (hh - ll) != 0 then (close - ll) / (hh - ll) * 100 else 50;
def k_c = k_raw - 50;
def macdValue = MACD(fastLength = fastLen, slowLength = slowLen, MACDLength = sigLen).Value;
def macdAvg = MACD(fastLength = fastLen, slowLength = slowLen, MACDLength = sigLen).Avg;
def hist = macdValue - macdAvg;
def stdevHist = StDev(hist, stdevLen);
def macd_c = if stdevHist != 0 then tanh(hist / (2.0 * stdevHist)) * 50 else 0;
def atr14 = Average(TrueRange(high, close, low), 14);
def roc_raw = if close[rocLen] != 0 then (close - close[rocLen]) / close[rocLen] * 100 else 0;
def roc_norm = roc_raw / (atr14 / close);
def roc_c = Max(-50, Min(50, roc_norm));
def combo_raw = if useROC then (wr_c + k_c + macd_c + roc_c) / 4.0 else (wr_c + k_c + macd_c) / 3.0;
def volSMA20 = Average(volume, 20);
def volRatio_raw = if useVolume and volSMA20 > 0 then Min(Log(1 + volume / volSMA20) * volSensitivity, 2.0) else 1.0;
def volRatio = Average(volRatio_raw, 3);
def combo = combo_raw * volRatio;
def volAvg5 = Average(volume, 5);
def volumeOK = !useVolume or volAvg5 >= minVolume;
def longSignal = volumeOK and Crosses(combo, osLevel, CrossingDirection.ABOVE) and (!useTrendFilter or trendUp);
def shortSignal = volumeOK and Crosses(combo, obLevel, CrossingDirection.BELOW) and (!useTrendFilter or trendDown);
# === MAIN PLOT (unchanged) ===
plot Composite = combo;
Composite.SetPaintingStrategy(PaintingStrategy.HISTOGRAM);
Composite.SetLineWeight(3);
Composite.AssignValueColor(
if combo > obLevel then Color.RED
else if combo < osLevel then Color.GREEN
else if combo > 0 then Color.BLUE
else Color.ORANGE
);
plot OB = obLevel; OB.SetDefaultColor(Color.RED); OB.SetStyle(Curve.SHORT_DASH);
plot Zero = 0; Zero.SetDefaultColor(Color.GRAY);
plot OS = osLevel; OS.SetDefaultColor(Color.GREEN); OS.SetStyle(Curve.SHORT_DASH);
AddCloud(obLevel, Composite, Color.RED, Color.RED);
AddCloud(Composite, osLevel, Color.GREEN, Color.GREEN);
plot LongArrow = if longSignal then osLevel - 20 else Double.NaN;
plot ShortArrow = if shortSignal then obLevel + 20 else Double.NaN;
LongArrow.SetPaintingStrategy(PaintingStrategy.ARROW_UP); LongArrow.SetDefaultColor(Color.GREEN); LongArrow.SetLineWeight(4);
ShortArrow.SetPaintingStrategy(PaintingStrategy.ARROW_DOWN); ShortArrow.SetDefaultColor(Color.RED); ShortArrow.SetLineWeight(4);
# ===============================================================
# PREDICTIVE STATUS LABELS – This is the magic you asked for
# ===============================================================
def rising = combo > combo[1];
def falling = combo < combo[1];
def extreme = AbsValue(combo) > 80;
AddLabel(yes,
if longSignal then "LONG SIGNAL – ENTERING BULL MODE"
else if shortSignal then "SHORT SIGNAL – ENTERING BEAR MODE"
else if combo > obLevel and falling then "DANGEROUSLY OVERBOUGHT – Reversal Likely"
else if combo > obLevel then "STRONG BULLISH – But Watch for Pullback"
else if combo < osLevel and rising then "DANGEROUSLY OVERSOLD – Reversal Likely"
else if combo < osLevel then "STRONG BEARISH – But Watch for Bounce"
else if combo > 50 and rising then "ACCELERATING BULLISH"
else if combo > 0 and rising then "BULLISH MOMENTUM BUILDING"
else if combo < -50 and falling then "ACCELERATING BEARISH"
else if combo < 0 and falling then "BEARISH MOMENTUM BUILDING"
else if extreme then "EXTREME MOMENTUM – Possible Exhaustion"
else "NEUTRAL / CHOP",
if longSignal then Color.DARK_GREEN
else if shortSignal then Color.DARK_RED
else if combo > obLevel then Color.RED
else if combo < osLevel then Color.GREEN
else if rising then Color.CYAN
else if falling then Color.MAGENTA
else Color.GRAY
);
# Secondary label: Trend + Volume context
AddLabel(yes,
(if trendUp then "Above EMA200 ↑" else "Below EMA200 ↓") + " | " +
(if volumeOK then "Volume CONFIRMED" else "Low Volume"),
if trendUp then Color.CYAN else Color.MAGENTA
);
# Tiny value label
AddLabel(yes, "Fat Tony: " + Round(combo, 1),
if combo > obLevel then Color.RED
else if combo < osLevel then Color.GREEN
else if combo > 0 then Color.BLUE
else Color.ORANGE
);
# === SCANNER PLOTS ===
plot scanLong = longSignal;
plot scanShort = shortSignal;
scanLong.Hide(); scanShort.Hide();