Fusion - Unified Signal For ThinkOrSwim

dap711

Active member
Plus
fusion.jpg

Why have 5 indicators on your screen when you can have just one! Let's do a Fusion.

mod note:
kVDh1yq.png


Python:
# Unified Signal (MACD + RSI + ATR + VWAP + Volume Pressure)
# + MACD Slope/Momentum + RSI Momentum ZLEMA + Adaptive EMA(8) Weight
# Accuracy features: dynamic majority, price confirmation, cooldown, optional ATR gate
# Outputs: BUY (1), SELL (-1), NONE (0) and colors price bars

# Tuning tips:
# Fewer whipsaws → raise confirmLen to 3 or cooldownBars to 3.
# More signals → lower majorityFrac to 0.6 or disable useATRGate.
# If volume pressure is noisy on your tickers → increase pressureEMA to 8–10 and/or pressureThreshold to ~0.12.

# Hidden Intent Composite (MACD/RSI/ATR + 12 Signals) - Fixed
# Clean compile: no AddChartColor, no invalid VWAP params, no ternary operator.
# Version 1.1

declare lower;

#-------------------------
# -------- Inputs --------
#-------------------------
input rsiBuy             = 55;
input rsiSell            = 45;
input atrLength          = 14;

# Feature toggles
input useVolumePressure          = yes;    # (1)
input useVWAPRejection           = yes;    # (4)
input useStopHuntReversal        = yes;    # (5)
input useMomentumVolumeDiv       = yes;    # (10)
input useRelativeStrength        = yes;    # (11)
input useOpeningDriveFailure     = yes;    # (12)
input usePOCShiftProxy           = yes;    # (7)  (lightweight proxy, not VolumeProfile)
input useRangeVolRegime          = yes;    # (9)
input useOBVDivergence           = yes;    # (3)
input useVWAPSlopeShift          = yes;    # extra context
input useEMA8Intent              = yes;    # your 8-EMA “3-vote” rule
input useATRTrendFilter          = yes;    # ATR% slope

# Weights
input wVolumePressure            = 2;
input wVWAPRejection             = 2;
input wStopHuntReversal          = 2;
input wMomentumVolumeDiv         = 2;
input wRelativeStrength          = 2;
input wOpeningDriveFailure       = 2;
input wPOCShiftProxy             = 2;
input wRangeVolRegime            = 1;
input wOBVDivergence             = 2;
input wVWAPSlopeShift            = 1;
input wEMA8Intent                = 3;
input wATRTrendFilter            = 1;

# Relative Strength
input rsSymbol                   = "QQQ";
input rsLen                      = 20;

# Opening Drive window (minutes after 09:30)
input odMinutes                  = 30;

# Smoothing
input smoothEMA                  = 5;

# Visuals
input showBubbles                = no;
input paintBars                  = yes;     # set yes to color price bars
input showComponents             = no;
input showScoreLabel             = yes;

#-------------------------
# ----- Base Series ------
#-------------------------
def na = Double.NaN;
def c  = close;
def o  = open;
def h  = high;
def l  = low;
def v  = volume;

# MACD
def macdDiff = MACD()."Diff";

# RSI
def rsi = RSI();

# ATR & ATR%
def atr = ATR(length = atrLength);
def atrPct = if c != 0 then atr / c * 100 else 0;

# EMA8
def ema = ExpAverage(c, 20);

# ---------- Custom Session VWAP (RTH reset at 09:30) ----------
def newDay = GetDay() <> GetDay()[1];
def rthStart = SecondsFromTime(0930) == 0;
def sessionReset = newDay or rthStart;

def tp = (h + l + c) / 3;
def cumPV = if sessionReset then tp * v else cumPV[1] + tp * v;
def cumV  = if sessionReset then v      else cumV[1] + v;
def vwap  = if cumV > 0 then cumPV / cumV else c;

# OBV (simple)
def obv = TotalSum(Sign(c - c[1]) * v);

# Relative Strength vs benchmark
def rs = c / close(rsSymbol);
def rsMA = Average(rs, rsLen);
def rsMA_slope = rsMA - rsMA[1];

# Helpers
def trange = h - l;
def body = AbsValue(c - o);
def upperWick = if c >= o then h - c else h - o;
def lowerWick = if c >= o then o - l else c - l;

# Opening Drive window (first N minutes from 09:30)
def inOD = SecondsFromTime(0930) >= 0 and SecondsFromTime(0930) < odMinutes * 60;

#-------------------------
# -- Hidden Intent Logic -
#-------------------------

# (1) Volume Pressure vs Price Direction
def rawVP = if trange > 0 then ((c - o) / trange) * v else 0;
def vpEMA = ExpAverage(rawVP, smoothEMA);
def priceDir = c - c[1];
def vpSignal = if useVolumePressure then
                  if vpEMA > 0 and priceDir >= 0 then 1 else
                  if vpEMA < 0 and priceDir <= 0 then -1 else 0
               else 0;

# (4) VWAP Rejections (within 0.1*ATR and wick-dominant rejection)
def nearVWAP = AbsValue(c - vwap) <= (atr * 0.1);
def rejectUp = nearVWAP and c > vwap and lowerWick > body;
def rejectDn = nearVWAP and c < vwap and upperWick > body;
def vwapRejSignal = if useVWAPRejection then
                       if rejectUp then 1 else
                       if rejectDn then -1 else 0
                    else 0;

# (5) Stop-run traps (liquidity hunts)
input swingLen = 10;
def swingHigh = Highest(h[1], swingLen);
def swingLow  = Lowest(l[1],  swingLen);
def stopRunUp = h > swingHigh and c < swingHigh;
def stopRunDn = l < swingLow  and c > swingLow;
def stopHuntSignal = if useStopHuntReversal then
                        if stopRunUp then -1 else
                        if stopRunDn then 1 else 0
                     else 0;

# (10) Momentum divergence (price HH/LL vs MACD Diff)
def hh = h > Highest(h[1], 5);
def ll = l < Lowest(l[1], 5);
def macdLowerHigh = macdDiff < macdDiff[1] and macdDiff[1] > macdDiff[2];
def macdHigherLow = macdDiff > macdDiff[1] and macdDiff[1] < macdDiff[2];
def momDivSignal = if useMomentumVolumeDiv then
                      if hh and macdLowerHigh then -1 else
                      if ll and macdHigherLow then 1 else 0
                   else 0;

# (11) Relative Strength slope
def rsSignal = if useRelativeStrength then
                  if rsMA_slope > 0 then 1 else
                  if rsMA_slope < 0 then -1 else 0
               else 0;

# (12) Opening Drive Failure (simple ORB logic)
rec orh = if inOD then Max(if IsNaN(orh[1]) then h else orh[1], h) else orh[1];
rec orl = if inOD then Min(if IsNaN(orl[1]) then l else orl[1], l) else orl[1];

def brokeUpOD  = !inOD and c[1] > orh and orh != 0;
def failedUp   = brokeUpOD and c < orh;
def brokeDnOD  = !inOD and c[1] < orl and orl != 0;
def failedDn   = brokeDnOD and c > orl;

def odFailSignal = if useOpeningDriveFailure then
                      if failedUp then -1 else
                      if failedDn then 1 else 0
                   else 0;

# (7) POC Shift Proxy (lightweight): use rolling VWAP vs rolling mean price
input pocLookback = 50;
def meanPrice = Average(c, pocLookback);
def pocSignal = if usePOCShiftProxy then
                   if vwap > meanPrice and vwap[1] <= meanPrice[1] then 1 else
                   if vwap < meanPrice and vwap[1] >= meanPrice[1] then -1 else 0
                else 0;

# (9) Range/Volume regime
def trueRange = TrueRange(h, c, l);
def rangeExp  = trueRange > Average(trueRange, 14);
def volExp    = v > Average(v, 20);
def regimeSignal = if useRangeVolRegime then
                      if rangeExp and !volExp then -1 else
                      if rangeExp and volExp then 1 else 0
                   else 0;

# (3) OBV divergence proxy
def priceUp2 = c > c[1] and c[1] > c[2];
def priceDn2 = c < c[1] and c[1] < c[2];
def obvDown  = obv < obv[1];
def obvUp    = obv > obv[1];
def obvDivSignal = if useOBVDivergence then
                      if priceUp2 and obvDown then -1 else
                      if priceDn2 and obvUp   then 1 else 0
                   else 0;

# VWAP slope shift
def vwapSlope = vwap - vwap[1];
def vwapSlopeSignal = if useVWAPSlopeShift then
                         if vwapSlope > 0 then 1 else
                         if vwapSlope < 0 then -1 else 0
                      else 0;

# EMA8 intent (3-vote if both O & C align)
def ema8Signal = if useEMA8Intent then
                    if c > ema then 1 else
                    if c < ema then -1 else 0
                 else 0;

# ATR trend filter
def atrSlope = atrPct - atrPct[1];
def atrSignal = if useATRTrendFilter then
                   if atrSlope > 0 then 1 else
                   if atrSlope < 0 then -1 else 0
                else 0;

#-------------------------
# ---- Scoring & Plots ---
#-------------------------
def scoreRaw =
    vpSignal            * wVolumePressure    +
    vwapRejSignal       * wVWAPRejection     +
    stopHuntSignal      * wStopHuntReversal  +
    momDivSignal        * wMomentumVolumeDiv +
    rsSignal            * wRelativeStrength  +
    odFailSignal        * wOpeningDriveFailure +
    pocSignal           * wPOCShiftProxy     +
    regimeSignal        * wRangeVolRegime    +
    obvDivSignal        * wOBVDivergence     +
    vwapSlopeSignal     * wVWAPSlopeShift    +
    ema8Signal          * wEMA8Intent        +
    atrSignal           * wATRTrendFilter;

def safeScoreRaw = if IsNaN(scoreRaw) then 0 else scoreRaw;
def scoreEMA = ExpAverage(safeScoreRaw, smoothEMA);


plot Composite = scoreEMA;
Composite.SetLineWeight(2);
Composite.AssignValueColor(
    if scoreEMA > 0 then Color.GREEN
    else if scoreEMA < 0 then Color.RED
    else Color.GRAY
);

plot ZeroLine = 0;
ZeroLine.SetDefaultColor(Color.GRAY);
ZeroLine.SetStyle(Curve.SHORT_DASH);

plot Thrust = scoreRaw;
Thrust.SetPaintingStrategy(PaintingStrategy.HISTOGRAM);
Thrust.SetLineWeight(2);
Thrust.AssignValueColor(
    if scoreRaw > 0 then Color.GREEN
    else if scoreRaw < 0 then Color.RED
    else Color.DARK_GRAY
);

# Optional components (thin debug lines)
def showC = showComponents;
plot pVP   = if showC then vpSignal        else na;
plot pVWAP = if showC then vwapRejSignal   else na;
plot pStop = if showC then stopHuntSignal  else na;
plot pDiv  = if showC then momDivSignal    else na;
plot pRS   = if showC then rsSignal        else na;
plot pOD   = if showC then odFailSignal    else na;
plot pPOC  = if showC then pocSignal       else na;
plot pReg  = if showC then regimeSignal    else na;
plot pOBV  = if showC then obvDivSignal    else na;
plot pVSlp = if showC then vwapSlopeSignal else na;
plot pE8   = if showC then ema8Signal      else na;
plot pATR  = if showC then atrSignal       else na;

pVP.SetDefaultColor(Color.CYAN);
pVWAP.SetDefaultColor(Color.YELLOW);
pStop.SetDefaultColor(Color.LIGHT_RED);
pDiv.SetDefaultColor(Color.WHITE);
pRS.SetDefaultColor(Color.LIGHT_GREEN);
pOD.SetDefaultColor(Color.MAGENTA);
pPOC.SetDefaultColor(Color.ORANGE);
pReg.SetDefaultColor(Color.LIGHT_GRAY);
pOBV.SetDefaultColor(Color.PINK);
pVSlp.SetDefaultColor(Color.LIGHT_ORANGE);
pE8.SetDefaultColor(Color.CYAN);
pATR.SetDefaultColor(Color.LIGHT_GRAY);
pVP.SetLineWeight(1);
pVWAP.SetLineWeight(1);
pStop.SetLineWeight(1);
pDiv.SetLineWeight(1);
pRS.SetLineWeight(1);
pOD.SetLineWeight(1);
pPOC.SetLineWeight(1);
pReg.SetLineWeight(1);
pOBV.SetLineWeight(1);
pVSlp.SetLineWeight(1);
pE8.SetLineWeight(1);
pATR.SetLineWeight(1);

#-------------------------
# ---- Visual Cues -------
#-------------------------
AddChartBubble(showBubbles and rejectUp,  scoreRaw, "VWAP↑Reject", Color.GREEN, yes);
AddChartBubble(showBubbles and rejectDn,  scoreRaw, "VWAP↓Reject", Color.RED,   no);
AddChartBubble(showBubbles and (hh and macdLowerHigh), scoreRaw, "Mom Div (Bear)", Color.RED, no);
AddChartBubble(showBubbles and (ll and macdHigherLow), scoreRaw, "Mom Div (Bull)", Color.GREEN, yes);


#-------------------------
# ---- Price Bar Paint ---
#-------------------------
AssignPriceColor(
    if paintBars then
        if scoreEMA > 0 then Color.Cyan
        else if scoreEMA < 0 then Color.Red
        else Color.GRAY
    else Color.CURRENT
);

#-------------------------
# ------ Label -----------
#-------------------------
def bullCount =
    Max(0, if IsNaN(vpSignal) then 0 else vpSignal) + Max(0, vwapRejSignal) + Max(0, stopHuntSignal) + Max(0, momDivSignal) +
    Max(0, rsSignal) + Max(0, odFailSignal) + Max(0, pocSignal) + Max(0, regimeSignal) +
    Max(0, obvDivSignal) + Max(0, vwapSlopeSignal) + Max(0, ema8Signal) + Max(0, atrSignal);

def bearCount =
    Max(0, if IsNaN(vpSignal) then 0 else -vpSignal) + Max(0, -vwapRejSignal) + Max(0, -stopHuntSignal) + Max(0, -momDivSignal) +
    Max(0, -rsSignal) + Max(0, -odFailSignal) + Max(0, -pocSignal) + Max(0, -regimeSignal) +
    Max(0, -obvDivSignal) + Max(0, -vwapSlopeSignal) + Max(0, -ema8Signal) + Max(0, -atrSignal);

AddLabel(showScoreLabel,
         "Intent " + AsText(Round(scoreEMA, 1)) +
         " | Bull " + bullCount + " vs Bear " + bearCount +
         " | MACDdiff " + AsText(Round(macdDiff, 2)) +
         " | RSI " + AsText(Round(rsi, 1)) +
         " | ATR% " + AsText(Round(atrPct, 2)) + "%",
         if scoreEMA > 0 then Color.GREEN else if scoreEMA < 0 then Color.RED else Color.GRAY);
 
Last edited by a moderator:

Join useThinkScript to post your question to a community of 21,000+ developers and traders.

Not the exact question you're looking for?

Start a new thread and receive assistance from our community.

87k+ Posts
624 Online
Create Post

The Market Trading Game Changer

Join 2,500+ subscribers inside the useThinkScript VIP Membership Club
  • Exclusive indicators
  • Proven strategies & setups
  • Private Discord community
  • ‘Buy The Dip’ signal alerts
  • Exclusive members-only content
  • Add-ons and resources
  • 1 full year of unlimited support

Frequently Asked Questions

What is useThinkScript?

useThinkScript is the #1 community of stock market investors using indicators and other tools to power their trading strategies. Traders of all skill levels use our forums to learn about scripting and indicators, help each other, and discover new ways to gain an edge in the markets.

How do I get started?

We get it. Our forum can be intimidating, if not overwhelming. With thousands of topics, tens of thousands of posts, our community has created an incredibly deep knowledge base for stock traders. No one can ever exhaust every resource provided on our site.

If you are new, or just looking for guidance, here are some helpful links to get you started.

What are the benefits of VIP Membership?
VIP members get exclusive access to these proven and tested premium indicators: Buy the Dip, Advanced Market Moves 2.0, Take Profit, and Volatility Trading Range. In addition, VIP members get access to over 50 VIP-only custom indicators, add-ons, and strategies, private VIP-only forums, private Discord channel to discuss trades and strategies in real-time, customer support, trade alerts, and much more. Learn all about VIP membership here.
How can I access the premium indicators?
To access the premium indicators, which are plug and play ready, sign up for VIP membership here.
Back
Top