STOCK INSIGHT — Homework 101 For ThinkOrSwim

atcsam

Market Structure Expert
Plus
STOCK INSIGHT
lYOMGOh.png


STOCK INSIGHT — SYSTEM OVERVIEW
A Multi‑Layer Decision Framework for Retail Traders
(Note: Resource‑heavy script — best used for homework)

1. Fundamentals — “Is this a good business?”
Stock Insight begins with a structural read of the company itself.
This layer evaluates:
  • Profitability
  • Cash Flow
  • Balance Sheet Strength
  • Returns & Efficiency
  • Growth
  • Long‑Term CAGR
These six categories roll into a 12‑point Fundamental Quality Score.​
Purpose:
Identify whether the underlying business is durable, fragile, improving, or deteriorating.​
Key Insight:
Fundamentals do not determine timing — they determine whether the stock deserves long‑term attention.


2. Valuation — “Is it priced fairly?”
Valuation is assessed relative to:
  • Growth
  • Profitability
  • Historical ranges
  • Market posture
A stock can be:
  • Cheap
  • Fair
  • Expensive
Purpose:
Determine whether the stock is a value opportunity, a premium compounder, or a potential trap.


3. Sector Context — “Is the environment helping or hurting?”
Sector analysis includes:
  • Sector Strength
  • RS–SPY Spread (Note: Sector selections in study options, default is SPY)
  • Trend
  • Divergence
  • Alignment
  • Confidence Score
Purpose:
Reveal whether the stock is being helped or hindered by its sector.​
Key Insight:
A stock can be a weak business but strong stock if the sector is leading — or the opposite.​

4. Sentiment — “Is the stock in play?”
A 0–100 composite score blending:
  • Trend
  • Volatility
  • Valuation posture
  • Growth posture
Sentiment classifications:
  • Strong Candidate
  • Tradeable
  • High Risk
  • Avoid
Purpose:
Filter out stocks that are not worth trading right now.

5. Environment (Overwatch) — “Is the timing safe?”
This is the real‑time behavioral engine:
  • MicroState
  • DOOM
  • Pressure
  • Exhaustion
  • Flow
  • Volatility Regime
  • Structure
Purpose:
Identify whether the environment is constructive, dangerous, or neutral.
This is the timing layer — the part that actually matters for entries and exits.

6. Retail Cues — “What should I do right now?”
The translation layer converts all system signals into simple, actionable guidance:
  • Accumulate on Dips
  • Wait for Pullback
  • High Volatility — Reduce Size
  • Blowoff Risk — Do Not Add
  • Base Building
  • Early Trend Starting
  • Sector Tailwind / No Tailwind / Sector Headwind
Purpose:
Provide a clean, honest, non‑hyped instruction based on the entire system.


Why a Low‑Quality Stock Can Still Be a “Strong Stock”
Stock Insight separates:
  • Business Strength (Fundamentals)
  • Market Strength (Relative Performance)
A stock can be:
  • Weak business + strong stock
  • Strong business + weak stock
  • Strong + strong
  • Weak + weak
This mirrors how professional desks classify names.

The Point
Stock Insight is not a signal generator.
It is a decision framework that mirrors institutional workflow:
  1. What is the business?
  2. What is it worth?
  3. What is the sector doing?
  4. Is sentiment supportive?
  5. Is the environment safe?
  6. What should retail do right now?
It compresses a professional desk’s process into a single, readable panel for us retail traders.


Exp:

IBM
2DfAIsx.png


AXON
NMmRHFJ.png


ALSN
UInTgF9.png


ADBE
wMQKLW5.png



Stock_Insight
(Study Link) http://tos.mx/!zgP1wJyI

(Homework Grid) http://tos.mx/!PCRzZvgY
Code:
Ruby:
# Stock - Insight
#Assebled: ATCSAM, playing it Forward 03/07/2026
# ---------------------------------------------------------
# DISCLAIMER
# This study is for informational and educational purposes only.
# It is NOT financial advice, trading advice, or a recommendation
# to buy or sell any security. All outputs, classifications, and
# cues are analytical tools designed to help traders understand
# market structure, sentiment, and context.
#
# Market conditions can change rapidly. All trading involves risk.
# You are solely responsible for your own investment decisions.
# Past performance does not guarantee future results.
# ---------------------------------------------------------

# Credits

# usethinkscript Community

#Fundamental Data Labels _Mobius 4/26/20 (found on OneNote)
#
# @MerryDay revised 4/21:
# my interpretation of positive/negative values; should be modified to meet your strategy
# then calculated an overall weighted score based on:

#[email protected]
#This study is used for Ken Rose's Generating Income with Dividend Stocks webcast Monday's 7PM ET

# CAGR Total Chart Timeframe
# Source: Pensar, 03.06.2021
# Modified by golden.nonce, 02.14.2022




#========================================================
# Fundamental Quality Engine

#========================================================

declare lower;

#-----------------------------
# Global Colors
#-----------------------------
DefineGlobalColor("Strong", CreateColor(0, 165, 0));          # Full Green
DefineGlobalColor("Neutral", Color.LIGHT_GRAY);               # Neutral
DefineGlobalColor("Weak", CreateColor(220, 180, 180));        # Soft Red/Pink
DefineGlobalColor("Bad", CreateColor(225, 0, 0));             # Red
DefineGlobalColor("Info", CreateColor(50, 200, 255));         # Cyan
DefineGlobalColor("Warn", CreateColor(200, 125, 0));          # Amber
DefineGlobalColor("Danger", CreateColor(255, 60, 60));

#-----------------------------
# Aggregation Helpers
#-----------------------------
def isDaily   = GetAggregationPeriod() == AggregationPeriod.DAY;
def isWeekly  = GetAggregationPeriod() == AggregationPeriod.WEEK;
def isMonthly = GetAggregationPeriod() == AggregationPeriod.MONTH;

#-----------------------------
# shared
# Actual earnings per event (TOS often returns N/A for CEFs, REITs, ETFs)
def AE = if IsNaN(GetActualEarnings()) then 0 else GetActualEarnings();

# Manual trailing earnings (TTM) based on bar type
def epsTTM_manual =
    if isDaily   then Sum(AE, 252)
    else if isWeekly  then Sum(AE, 52)
    else if isMonthly then Sum(AE, 12)
    else 0;

# Safe EPS (fallback to tiny positive number to avoid divide-by-zero)
def _epsTTM_manual = if IsNaN(epsTTM_manual) or epsTTM_manual == 0
                     then 0.0001
                     else epsTTM_manual;


#-----------------------------
# Dividend Yield & Payout
#-----------------------------
def divYieldPct = if IsNaN(GetYield()) then Double.NaN else Round(GetYield() * 100, 2);



rec DCont = if IsNaN(GetDividend()) then DCont[1] else GetDividend();
def divAnnual = if DCont <> 0 then DCont * 4 else Double.NaN;

def payoutRatio =
    if !IsNaN(divAnnual) and epsTTM_manual != 0 and !IsNaN(epsTTM_manual)
    then Round(divAnnual * 100 / epsTTM_manual, 2)
    else Double.NaN;



#-----------------------------
# 52-Week High Context
#-----------------------------
def len52 =
    if isDaily   then 252
    else if isWeekly  then 52
    else if isMonthly then 12
    else Double.NaN;

def top52 = Highest(high, len52);

def pctOffHigh =
    if top52 != 0 and !IsNaN(top52)
    then (close / top52) - 1
    else Double.NaN;

def newHigh = high == top52;


#-----------------------------
# Manual EPS / PE (AE-based)
#-----------------------------

# Actual earnings per event (TOS often returns N/A for CEFs, REITs, ETFs)
# Manual trailing earnings (TTM) based on bar type

# Raw PE calculation
def PE_raw = Round(close / _epsTTM_manual, 2);

# Trap missing/invalid EPS as extremely high PE
def PE = if IsNaN(PE_raw) or PE_raw < 0 then 999 else PE_raw;
def PE_safe = if IsNaN(PE) then 999 else PE;

# PE trap flag
def PE_isTrapped = PE >= 999;



#-----------------------------
# SAFE INPUTS
#-----------------------------
def _pctOffHigh = if IsNaN(pctOffHigh) then 0 else pctOffHigh;
def _divYieldPct = if IsNaN(divYieldPct) then 0 else divYieldPct;



# -----------------------------
# SAFE, CAGR
# -----------------------------


def agg = AggregationPeriod.YEAR;
def c = close(period = agg);
def yearbars = if c then yearbars[1] + 1 else yearbars[1];
def o = First(open(period = agg));
def CAGR = Power(c / o, 1 / yearbars) - 1;

def hasYears = yearbars >= 3 and !IsNaN(o) and o > 0 and !IsNaN(c);
def CAGR_safe = if hasYears then CAGR else Double.NaN;



#-----------------------------
# Core Fundamental Metrics
#-----------------------------
def gpMargin =
    if IsNaN(GrossProfitMargin()) then gpMargin[1] else GrossProfitMargin();
def opMargin =
    if IsNaN(OperatingProfitMargin()) then opMargin[1] else OperatingProfitMargin();
def netMargin =
    if IsNaN(NetProfitMargin()) then netMargin[1] else NetProfitMargin();

def fcfPerShare =
    if IsNaN(FreeCashFlowPerShare()) then fcfPerShare[1] else FreeCashFlowPerShare();
def epsTTM =
    if IsNaN(EarningsPerShareTTM()) then epsTTM[1] else EarningsPerShareTTM();

def fixCov =
    if IsNaN(FixedChargeCoverageRatio()) then fixCov[1] else FixedChargeCoverageRatio();

def curRatio =
    if IsNaN(CurrentRatio()) then curRatio[1] else CurrentRatio();
def quickRatio =
    if IsNaN(QuickRatio()) then quickRatio[1] else QuickRatio();
def ltdToCap =
    if IsNaN(LongTermDebtToCapital()) then ltdToCap[1] else LongTermDebtToCapital();

def roa =
    if IsNaN(ReturnOnAssets()) then roa[1] else ReturnOnAssets();
def roe =
    if IsNaN(ReturnOnEquity()) then roe[1] else ReturnOnEquity();
def assetTurn =
    if IsNaN(TotalAssetTurnover()) then assetTurn[1] else TotalAssetTurnover();

def salesPerShare =
    if IsNaN(SalesPerShare()) then salesPerShare[1] else SalesPerShare();

#-----------------------------
# Category Scoring (0–3 each)
#-----------------------------

# Profitability
def scoreProfitability =
    if gpMargin > 0 and opMargin > 0 and netMargin > 0 then 3
    else if (gpMargin > 0 and (opMargin > 0 or netMargin > 0)) then 2
    else if gpMargin > 0 or opMargin > 0 or netMargin > 0 then 1
    else 0;


# Cash Flow
def scoreCashFlow =
    if fcfPerShare > 0 and epsTTM > 0 and fixCov >= 1 then 3
    else if (fcfPerShare > 0 and epsTTM > 0) or (fcfPerShare > 0 and fixCov >= 1) then 2
    else if fcfPerShare > 0 or epsTTM > 0 or fixCov >= 1 then 1
    else 0;



# Balance Sheet
def scoreBalance =
    if quickRatio >= 1 and curRatio >= 1 and ltdToCap < 40 then 3
    else if (quickRatio >= 1 and curRatio >= 1) or (curRatio >= 1 and ltdToCap < 60) then 2
    else if quickRatio >= 1 or curRatio >= 1 then 1
    else 0;



# Returns & Efficiency
def scoreReturns =
    if roa >= 10 and roe >= 15 and assetTurn > 1 then 3
    else if (roa >= 5 and roe >= 10) or (roe >= 15 and assetTurn > 0.8) then 2
    else if roa > 0 or roe > 0 or assetTurn > 0.5 then 1
    else 0;


# Growth
def scoreGrowth =
    if  CAGR > 0.08 and salesPerShare > 0 then 3
    else if CAGR >= 0.03 and salesPerShare > 0 then 2
    else if CAGR > 0 or salesPerShare > 0 then 1
    else 0;


#-----------------------------
# Final Quality Score (0–12)
#-----------------------------
def rawTotal =
    scoreProfitability +
    scoreCashFlow +
    scoreBalance +
    scoreReturns +
    scoreGrowth;

def qualityScore = Round(rawTotal * 12 / 15, 0);



# ------------------
# Label Hierarchy


AddLabel(
    yes,
    "P/E : " +
    (if PE_isTrapped
     then "N/A (High)"
     else AsText(PE)),
    if PE_isTrapped then GlobalColor("Danger")
    else if PE < 20 then GlobalColor("Strong")
    else if PE < 40 then GlobalColor("Warn")
    else GlobalColor("Weak")
);

AddLabel(!IsNaN(divYieldPct),
         "Dividend Yield: " + divYieldPct + "%",
         if IsNaN(divYieldPct) then GlobalColor("Neutral")
         else if divYieldPct < 2 then GlobalColor("Neutral")
         else if divYieldPct <= 6 then GlobalColor("Strong")
         else GlobalColor("Warn"));

AddLabel(!IsNaN(payoutRatio),
         "Payout Ratio: " + payoutRatio + "%",
         if IsNaN(payoutRatio) then GlobalColor("Neutral")
         else if payoutRatio < 60 then GlobalColor("Strong")
         else if payoutRatio <= 100 then GlobalColor("Warn")
         else GlobalColor("Bad"));


AddLabel(!IsNaN(pctOffHigh) and !newHigh,
         AsPercent(pctOffHigh) + " off 52 Wk High: ",
         if pctOffHigh >= -0.10 then GlobalColor("Strong")
         else if pctOffHigh >= -0.25 then GlobalColor("Warn")
         else GlobalColor("Weak"));

AddLabel(newHigh,
         "New 52-Week High TODAY",
         GlobalColor("Info"));



AddLabel(1,
    if hasYears
    then "CAGR: " + AsPercent(CAGR_safe) + " " + (yearbars - 1) + "/Yrs"
    else "CAGR: N/A (Insufficient Data)",
    if hasYears and CAGR_safe > 0.08 then GlobalColor("Strong")
    else if hasYears and CAGR_safe >= 0.03 then CreateColor(120, 200, 120)
    else GlobalColor("Weak")
);

AddLabel(yes,
         "Profitability: " +
         (if scoreProfitability == 3 then "Strong"
          else if scoreProfitability == 2 then "Moderate"
          else if scoreProfitability == 1 then "Weak"
          else "Bad"),
         if scoreProfitability == 3 then GlobalColor("Strong")
         else if scoreProfitability == 2 then GlobalColor("Neutral")
         else if scoreProfitability == 1 then GlobalColor("Weak")
         else GlobalColor("Bad"));

AddLabel(yes,
         "Cash Flow: " +
         (if scoreCashFlow == 3 then "Strong"
          else if scoreCashFlow == 2 then "Moderate"
          else if scoreCashFlow == 1 then "Weak"
          else "Bad"),
         if scoreCashFlow == 3 then GlobalColor("Strong")
         else if scoreCashFlow == 2 then GlobalColor("Neutral")
         else if scoreCashFlow == 1 then GlobalColor("Weak")
         else GlobalColor("Bad"));

AddLabel(yes,
         "Balance Sheet: " +
         (if scoreBalance == 3 then "Strong"
          else if scoreBalance == 2 then "Moderate"
          else if scoreBalance == 1 then "Weak"
          else "Bad"),
         if scoreBalance == 3 then GlobalColor("Strong")
         else if scoreBalance == 2 then GlobalColor("Neutral")
         else if scoreBalance == 1 then GlobalColor("Weak")
         else GlobalColor("Bad"));

AddLabel(yes,
         "Returns/Efficiency: " +
         (if scoreReturns == 3 then "Strong"
          else if scoreReturns == 2 then "Moderate"
          else if scoreReturns == 1 then "Weak"
          else "Bad"),
         if scoreReturns == 3 then GlobalColor("Strong")
         else if scoreReturns == 2 then GlobalColor("Neutral")
         else if scoreReturns == 1 then GlobalColor("Weak")
         else GlobalColor("Bad"));

AddLabel(yes,
         "Growth: " +
         (if scoreGrowth == 3 then "Strong"
          else if scoreGrowth == 2 then "Moderate"
          else if scoreGrowth == 1 then "Weak"
          else "Bad"),
         if scoreGrowth == 3 then GlobalColor("Strong")
         else if scoreGrowth == 2 then CreateColor(120, 200, 120)
         else if scoreGrowth == 1 then GlobalColor("Weak")
         else GlobalColor("Bad"));
#------ FontSize.LARGE size test -----------------
AddLabel(yes,
         "Fundamental Quality: " + qualityScore + " / 12",
         if qualityScore >= 10 then GlobalColor("Strong")
         else if qualityScore >= 7 then CreateColor(120, 200, 120)
         else if qualityScore >= 4 then GlobalColor("Weak")
         else GlobalColor("Bad"), size = FontSize.Medium);

#Spcer
#addLabel (Yes,"-----------------------",size = FontSize.SMALL);
#===========================================================
# VALUATION ENGINE
#===========================================================

#-----------------------------------------
# Valuation Score (0–3)
#-----------------------------------------

# Missing PE → treat as expensive
def valuationScore =
    if PE_safe == 999 then 1

    # Undervalued: Cheap PE AND supportive discount/yield
    else if PE_safe < 15 and (_pctOffHigh <= -0.25 or _divYieldPct > 3) then 3

    # Fair: Mid PE OR moderate discount OR moderate yield
    else if (PE_safe >= 15 and PE_safe <= 25)
         or (_pctOffHigh > -0.25 and _pctOffHigh <= -0.10)
         or (_divYieldPct >= 1 and _divYieldPct <= 3) then 2

    # Expensive: High PE AND no discount AND low yield
    else if PE_safe > 25 and _pctOffHigh > -0.10 and _divYieldPct < 1 then 1

    else 2;  # Default to Fair if mixed signals


AddLabel(
    yes,
    "Valuation: " +
    (if valuationScore == 3 then "UnderValued"
     else if valuationScore == 2 then "Fair"
     else if valuationScore == 1 then "Expensive"
     else "Very Expensive"),
    if valuationScore == 3 then GlobalColor("Strong")
    else if valuationScore == 2 then CreateColor(120, 200, 120)
    else if valuationScore == 1 then GlobalColor("Warn")
    else GlobalColor("Danger"),size = FontSize.Medium
);

#===========================================================
# DISCOUNT / VALUE OPPORTUNITY
#===========================================================

def isHighQuality = qualityScore >= 9;
def isDiscounted = pctOffHigh <= -0.20;
def isFairOrCheap = valuationScore >= 2;

def valueOpportunity = isHighQuality and isDiscounted and isFairOrCheap;

AddLabel(valueOpportunity,
         "Value Opportunity: High Quality, Discounted",
         CreateColor(120, 200, 120));

AddLabel(!valueOpportunity and isHighQuality and isDiscounted,
         "Discounted, but valuation rich",
         GlobalColor("Warn"));

AddLabel(!valueOpportunity and isHighQuality and !isDiscounted,
         "High Quality, but not discounted",
         GlobalColor("Neutral"));

#===========================================================
# NARRATIVE LAYER
#===========================================================

#-----------------------------------------
# 1. Cheap but Extended
#-----------------------------------------
def cheapButExtended =
    PE_safe < 15 and pctOffHigh > -0.05;

AddLabel(cheapButExtended,
         "Cheap but Extended (Wait for Pullback)",
         GlobalColor("Warn"));

#-----------------------------------------
# 2. High Quality on Sale
#-----------------------------------------
def highQualityOnSale =
    qualityScore >= 9 and pctOffHigh <= -0.20 and valuationScore >= 2;

AddLabel(highQualityOnSale,
         "High Quality on Sale (Institutional Accumulation Zone)",
         CreateColor(120, 200, 120));

#-----------------------------------------
# 3. Value Trap Risk
#-----------------------------------------
def valueTrapRisk =
    valuationScore == 3 and qualityScore <= 4 and (epsTTM < 0 or fcfPerShare < 0);

AddLabel(valueTrapRisk,
         "Value Trap Risk (Cheap for a Reason)",
         GlobalColor("Bad"));

#-----------------------------------------
# 4. Rich Valuation but Improving Fundamentals
#-----------------------------------------
rec improvingQuality = if qualityScore > qualityScore[1] then 1 else 0;

def richValImproving =
    valuationScore == 1 and improvingQuality == 1;

AddLabel(richValImproving,
         "Rich Valuation but Improving Fundamentals",
         GlobalColor("Warn"));

#-----------------------------------------
# 5. Speculative Growth — Fundamentals Not Applicable
#-----------------------------------------
def speculativeGrowth =
    qualityScore <= 3 and fcfPerShare < 0 and epsTTM < 0 and ltdToCap > 50;

AddLabel(speculativeGrowth,
         "Speculative Growth — Fundamentals Not Applicable",
         GlobalColor("Bad"));

#-----------------------------------------
# 6. Cash-Flow Machine Trading at a Premium
#-----------------------------------------
def cashFlowMachine =
    fcfPerShare > 0 and epsTTM > 0 and valuationScore == 1 and qualityScore >= 9;

AddLabel(cashFlowMachine,
         "Cash-Flow Machine Trading at a Premium",
         GlobalColor("Info"));

#===========================================================
# LONG-TERM CANDIDATE / ACCUMULATION
#===========================================================

def longTermCandidate =
    qualityScore >= 9 and
    valuationScore >= 2 and
    pctOffHigh <= -0.05 and
    pctOffHigh >= -0.40 and
    fcfPerShare > 0 and
    epsTTM > 0;

AddLabel(longTermCandidate,
         "! Long-Term Candidate (Accumulate)",
         Color.CYAN);


#===============================
# Sector Strength / Alignment Panel
#===============================



#-------------------------------
# USER INPUTS
#-------------------------------
input sector =
{
    default Market_SPY,
    Materials,
    Energy,
    Financials,
    Industrials,
    Technology,
    Consumer_Staples,
    Utilities,
    Healthcare,
    Consumer_Discretionary,
    Real_Estate,
    Communications
};

input rsLength = 20;
input rsSmoothing = 5;

input showRS = no;
input showSPYTrend = no;

#-------------------------------
# SECTOR SYMBOL RESOLUTION
#-------------------------------
def na = Double.NaN;

def isSPY  = sector == sector.Market_SPY;
def isMAT  = sector == sector.Materials;
def isENE  = sector == sector.Energy;
def isFIN  = sector == sector.Financials;
def isIND  = sector == sector.Industrials;
def isTECH = sector == sector.Technology;
def isCST  = sector == sector.Consumer_Staples;
def isUTL  = sector == sector.Utilities;
def isHLT  = sector == sector.Healthcare;
def isCSD  = sector == sector.Consumer_Discretionary;
def isRE   = sector == sector.Real_Estate;
def isCOM  = sector == sector.Communications;

def spyClose  = close("SPY");
def matClose  = close("XLB");
def eneClose  = close("XLE");
def finClose  = close("XLF");
def indClose  = close("XLI");
def techClose = close("XLK");
def cstClose  = close("XLP");
def utlClose  = close("XLU");
def hltClose  = close("XLV");
def csdClose  = close("XLY");
def reClose   = close("XLRE");
def comClose  = close("XLC");

def sectorClose =
    if isSPY  then spyClose  else
    if isMAT  then matClose  else
    if isENE  then eneClose  else
    if isFIN  then finClose  else
    if isIND  then indClose  else
    if isTECH then techClose else
    if isCST  then cstClose  else
    if isUTL  then utlClose  else
    if isHLT  then hltClose  else
    if isCSD  then csdClose  else
    if isRE   then reClose   else
    if isCOM  then comClose  else
    na;

#-------------------------------
# RELATIVE STRENGTH ENGINE
#-------------------------------
def okData = !IsNaN(close) and !IsNaN(sectorClose);

def rawRS = if okData and sectorClose != 0 then close / sectorClose else na;
def baseRS = if !IsNaN(rawRS[rsLength]) and rawRS[rsLength] != 0 then rawRS / rawRS[rsLength] else na;
def sectorRS = ExpAverage(baseRS, rsSmoothing);


def normRS_unweighted = sectorRS - 1;


#-------------------------------
# SPY TREND (UNWEIGHTED, PLOTTED)
#-------------------------------
def spyTrendChange = spyClose - spyClose[rsLength];
def spyTrendPct = if spyClose[rsLength] != 0 then spyTrendChange / spyClose[rsLength] else 0;


#-------------------------------
# VOLATILITY-WEIGHTED RS (LOGIC ONLY)
#-------------------------------
def atrr = Average(TrueRange(high, close, low), rsLength);
def atrNorm = if close != 0 then atrr / close else 0;

def volFactor = Sqrt(atrNorm);

def normRS_weighted =
    if volFactor != 0 then (sectorRS - 1) / volFactor else 0;

#-------------------------------
# SPREAD (WEIGHTED RS - RAW SPY TREND)
#-------------------------------
def spread1 = normRS_weighted - spyTrendPct;

AddLabel(yes,
    "Sector: " +
    (if isSPY  then "Market (SPY)" else
     if isMAT  then "Materials" else
     if isENE  then "Energy" else
     if isFIN  then "Financials" else
     if isIND  then "Industrials" else
     if isTECH then "Technology" else
     if isCST  then "Consumer Staples" else
     if isUTL  then "Utilities" else
     if isHLT  then "Healthcare" else
     if isCSD  then "Consumer Discretionary" else
     if isRE   then "Real Estate" else
     if isCOM  then "Communications" else
     "Unknown"),
    Color.WHITE
);


AddLabel(yes,
    "RS–SPY Spread: " + AsPercent(spread1),
    if spread1 > 0 then Color.GREEN else
    if spread1 < 0 then Color.RED else
    Color.GRAY
);

#-------------------------------
# SECTOR STRENGTH (NUMERIC CODE)
#-------------------------------
def strengthCode =
    if sectorRS > 1 then 1 else
    if sectorRS < 1 then -1 else
    0;

#-------------------------------
# 5-STATE TREND MODEL
#-------------------------------
def trendChange = if okData and !IsNaN(sectorClose[rsLength]) then sectorClose - sectorClose[rsLength] else 0;
def trendPct    = if okData and sectorClose[rsLength] != 0 then trendChange / sectorClose[rsLength] else 0;

def strongUpThresh   = 0.04;
def weakUpThresh     = 0.01;
def strongDownThresh = -0.04;
def weakDownThresh   = -0.01;

def trendCode =
    if trendPct >= strongUpThresh then 1 else
    if trendPct >= weakUpThresh   then 2 else
    if trendPct <= strongDownThresh then -1 else
    if trendPct <= weakDownThresh   then -2 else
    0;

#-------------------------------
# DIVERGENCE
#-------------------------------
def stockStrong = sectorRS > 1;
def stockWeak   = sectorRS < 1;

def divCode =
    if (trendCode == -1 or trendCode == -2) and stockStrong then 1 else
    if (trendCode == 1  or trendCode == 2)  and stockWeak   then -1 else
    0;

#-------------------------------
# ALIGNMENT
#-------------------------------
def alignmentCode =
    if strengthCode == 1 and stockStrong then 1 else
    if strengthCode == -1 and stockStrong then 2 else
    if strengthCode == 1 and stockWeak   then 3 else
    if strengthCode == -1 and stockWeak  then 4 else
    0;


#-------------------------------
# CONFIDENCE SCORE
#-------------------------------

# RS Strength Component (0–1)
def confRS = Min(1, AbsValue(normRS_weighted) / 0.5);

# Agreement Component (RS vs SPY)
def confAgreement =
    if normRS_weighted > 0 and spyTrendPct <= 0 then 1
    else if normRS_weighted < 0 and spyTrendPct >= 0 then 1
    else 0.5;

# Smoothness Component (RS stability)
def rsVol = StDev(normRS_unweighted, rsLength);
def confSmooth = 1 - Min(1, rsVol / 0.1);

# Final Confidence Score (0–1)
def confidence =
    (confRS * 0.5) +
    (confAgreement * 0.3) +
    (confSmooth * 0.2);

AddLabel(yes,
    "Confidence: " + AsPercent(confidence),
    if confidence > 0.75 then Color.GREEN
    else if confidence > 0.5 then Color.DARK_GREEN
    else if confidence > 0.35 then Color.ORANGE
    else Color.RED
);


#-------------------------------
# LABELS
#-------------------------------

AddLabel(yes,
    if strengthCode == 1 then "Strong (Leading)" else
    if strengthCode == -1 then "Weak (Lagging)" else
    "Neutral",
    if strengthCode == 1 then Color.GREEN else
    if strengthCode == -1 then Color.RED else
    Color.GRAY
);

AddLabel(yes,
    (if isSPY then "SPY Trend: " else "Sector Trend: ") +
    (if trendCode == 1  then "Strong Up" else
     if trendCode == 2  then "Weak Up" else
     if trendCode == -2 then "Weak Down" else
     if trendCode == -1 then "Strong Down" else
     "Drift"),
    if trendCode == 1  then Color.GREEN else
    if trendCode == 2  then Color.DARK_GREEN else
    if trendCode == -2 then Color.DARK_RED else
    if trendCode == -1 then Color.RED else
    Color.GRAY
);

AddLabel(yes,
    "Divergence: " +
    (if divCode == 1 then "Bullish" else
     if divCode == -1 then "Bearish" else
     "None"),
    if divCode == 1 then Color.GREEN else
    if divCode == -1 then Color.RED else
    Color.GRAY
);

AddLabel(yes,
    "Alignment: " +
    (if alignmentCode == 1 then "Leader in Strong Sector" else
     if alignmentCode == 2 then "Leader in Weak Sector" else
     if alignmentCode == 3 then "Laggard in Strong Sector" else
     if alignmentCode == 4 then "Laggard in Weak Sector" else
     "Neutral"),
    if alignmentCode == 1 then Color.GREEN else
    if alignmentCode == 2 then Color.DARK_GREEN else
    if alignmentCode == 3 then Color.ORANGE else
    if alignmentCode == 4 then Color.RED else
    Color.GRAY
);



############################################
# OVERWATCH — CONDENSED CORE ENGINE
############################################

input price = close;

############################################
# PART A — Z ENGINE + MICROSTATE + PRESSURE
############################################

# --- Z-Score Engine ---
def zMean50 = Average(price, 50);
def zDev50  = StDev(price, 50);
def z50     = if zDev50 != 0 then (price - zMean50) / zDev50 else 0;

def zMean30 = Average(price, 30);
def zDev30  = StDev(price, 30);
def z30     = if zDev30 != 0 then (price - zMean30) / zDev30 else 0;

def zMean20 = Average(price, 20);
def zDev20  = StDev(price, 20);
def z20     = if zDev20 != 0 then (price - zMean20) / zDev20 else 0;

def zMean10 = Average(price, 10);
def zDev10  = StDev(price, 10);
def z10     = if zDev10 != 0 then (price - zMean10) / zDev10 else 0;

def zScore =
    if AbsValue(z50) > 3 then z10 else
    if AbsValue(z50) > 2 then z20 else
    if AbsValue(z50) > 1.5 then z30 else
    z50;

def zSlope = zScore - zScore[1];

# Secondary Z
def z2Mean = Average(zScore, 20);
def z2Dev  = StDev(zScore, 20);
def z2     = if z2Dev != 0 then (zScore - z2Mean) / z2Dev else 0;

# --- STAR-C Baseline (structural reference only) ---
def smaBase = Average(price, 6);
def atr = Average(TrueRange(high, close, low), 15);
def upperBand = smaBase + 2 * atr;
def lowerBand = smaBase - 2 * atr;

# --- Dome Engine ---
def zStretch = Max(0, AbsValue(zScore) - 1.6);
def zCurve = Power(zStretch, 1.5);

def atrMean = Average(atr, 20);
def volWeight = if atrMean != 0 then atr / atrMean else 1;

def zExpandRaw = zCurve * atr * volWeight;
def zExpand = ExpAverage(zExpandRaw, 3);

def domeSmooth = ExpAverage(zExpand, 5);
def domeROC = domeSmooth - domeSmooth[3];

def domeNorm =
    if HighestAll(domeSmooth) == LowestAll(domeSmooth)
    then 0
    else 100 * (domeSmooth - LowestAll(domeSmooth)) /
         (HighestAll(domeSmooth) - LowestAll(domeSmooth));

def domeCompression = domeROC < 0;
def domeExpansion   = domeROC > 0;

# Doom regime (kept for internal hybrid use)
def doomRegime =
    if domeCompression then 0
    else if domeExpansion then 2
    else 1;

# --- Trend Quality × Volatility ---
def tq_source = close;
def tq_delta = AbsValue(tq_source - tq_source[1]);
def tq_maxDelta = Highest(tq_delta, 200);
def tq_safeMaxDelta = if tq_maxDelta == 0 then 1 else tq_maxDelta;
def tq_accelFactor = tq_delta / tq_safeMaxDelta;

def tq_dynLen = 5 + ((tq_source + Highest(tq_source,200)) / (2*Highest(tq_source,200))) * (50 - 5);
def tq_alphaBase = 2 / (tq_dynLen + 1);
def tq_alphaRaw = tq_alphaBase * (1 + tq_accelFactor * 5);
def tq_alpha = Min(1, tq_alphaRaw);

rec tq_dynEMA =
    if BarNumber() == 1 then tq_source
    else tq_alpha * tq_source + (1 - tq_alpha) * tq_dynEMA[1];

def tq_speed = tq_dynEMA - tq_dynEMA[1];
def tq_trendSpeed = HullMovingAvg(tq_speed, 5);
def tq_trendSpeedSmooth = ExpAverage(tq_trendSpeed, 3);

def tq_min = Lowest(tq_trendSpeedSmooth, 100);
def tq_max = Highest(tq_trendSpeedSmooth, 100);

def tq_normQ =
    if tq_max == tq_min then 0
    else (tq_trendSpeedSmooth - tq_min) / (tq_max - tq_min);

def microTrend =
    if tq_normQ >= 0.75 then 3 else
    if tq_normQ >= 0.50 then 2 else
    if tq_normQ >= 0.25 then 1 else 0;

def tqVolHybrid = microTrend * doomRegime;

# --- Bias Engine ---
def ema3 = ExpAverage(close, 3);
def ema3Slope = ema3 - ema3[1];
def mom3 = close - close[3];

def upBodies =
    (close > open) +
    (close[1] > open[1]) +
    (close[2] > open[2]);

def dnBodies =
    (close < open) +
    (close[1] < open[1]) +
    (close[2] < open[2]);

def bullBias = ema3Slope > 0 and mom3 > 0 and upBodies >= 2;
def bearBias = ema3Slope < 0 and mom3 < 0 and dnBodies >= 2;

# --- Micro Diagnostics ---
def spread = high - low;
def avgSpread = Average(spread, 20);
def avgVol = Average(volume, 20);

def rotRaw = (spread / avgSpread) * (volume / avgVol);
def rotNorm = if HighestAll(rotRaw) == 0 then 0 else rotRaw / HighestAll(rotRaw);

def trendMa = ExpAverage(price, 50);
def trendEnergy = trendMa - trendMa[2];
def trendDecel = trendEnergy < 0;

def zPhaseDown = zSlope < 0;

# --- Commitment & Stability ---
def barRange = high - low;
def bodySize = AbsValue(close - open);
def safeRange = if barRange == 0 then 0.0001 else barRange;
def bodyFrac = bodySize / safeRange;

def bullBar = close > open;
def bearBar = close < open;

def followThroughUp = bullBar and close > close[1];
def followThroughDown = bearBar and close < close[1];

def upperWick = high - Max(open, close);
def lowerWick = Min(open, close) - low;

def wickAlignedBull = bullBar and lowerWick > upperWick;
def wickAlignedBear = bearBar and upperWick > lowerWick;

def overlap =
    (high <= high[1] and low >= low[1]) or
    (high[1] <= high and low[1] >= low);

def dcRaw =
    (if bodyFrac > 0.5 then 1 else 0) +
    (if followThroughUp or followThroughDown then 1 else 0) +
    (if wickAlignedBull or wickAlignedBear then 1 else 0) +
    (if !overlap then 1 else 0);

def dcNorm = dcRaw / 4;

rec dcSmooth =
    if IsNaN(dcSmooth[1]) then dcNorm
    else dcSmooth[1] + 0.2 * (dcNorm - dcSmooth[1]);

def dirBar = if close > open then 1 else if close < open then -1 else 0;
def dirSlope = if ema3Slope > 0 then 1 else if ema3Slope < 0 then -1 else 0;
def dirMom = if mom3 > 0 then 1 else if mom3 < 0 then -1 else 0;

def dsNormRaw =
    (AbsValue(Sum(dirBar,5))/5 +
     AbsValue(Sum(dirSlope,5))/5 +
     AbsValue(Sum(dirMom,5))/5) / 3;

rec dsSmooth =
    if IsNaN(dsSmooth[1]) then dsNormRaw
    else dsSmooth[1] + 0.2 * (dsNormRaw - dsSmooth[1]);

def dcNormH = Max(0, Min(1, dcSmooth));
def dsNorm  = Max(0, Min(1, dsSmooth));

# --- Volatility Burst ---
def volBurst = domeROC > domeSmooth * 0.15;

# --- MicroState (0–3) ---
def microState =
    if domeCompression and !volBurst and dsNorm >= 0.5 then 0 else
    if domeCompression and  volBurst then 1 else
    if domeExpansion   and !volBurst and dsNorm >= 0.5 then 2 else
    if domeExpansion   and  volBurst then 3 else 0;

############################################
# PART B — DANGER ENGINE + P-STATE LOGIC
############################################

# --- Danger Channels ---
def d_dome = domeNorm >= 70 or domeNorm <= 30;
def d_micro = microState == 3;
def d_z = zPhaseDown;
def d_rot = rotNorm > 0.6;
def d_trend = trendDecel;
def d_dc = dcNormH < 0.5;
def d_ds = dsNorm < 0.5;

def nonDomeScore =
    (if d_micro then 1 else 0) +
    (if d_z then 1 else 0) +
    (if d_rot then 1 else 0) +
    (if d_trend then 1 else 0) +
    (if d_dc then 1 else 0) +
    (if d_ds then 1 else 0);

# --- MicroPressure → P-State (0–3) ---
def microPressure =
    (if domeCompression then 1 else 0) +
    (if zPhaseDown then 1 else 0) +
    (if rotNorm > 0.6 then 1 else 0) +
    (if trendDecel then 1 else 0) +
    (if dcNormH < 0.5 then 1 else 0) +
    (if dsNorm < 0.5 then 1 else 0);

def pState =
    if microPressure == 0 then 0 else
    if microPressure == 1 then 1 else
    if microPressure == 2 or microPressure == 3 then 2 else
    if microPressure == 4 or microPressure == 5 then 3 else 4;

# --- P2 Danger ---
def p2Danger =
    pState == 2 and
    (
        (d_dome and nonDomeScore >= 1) or
        (!d_dome and nonDomeScore >= 3)
    );

# --- Pressure Descriptor (Early vs Light) ---
def wasP2 = pState[1] == 2;
def wasDanger = p2Danger[1];

def lightPressure = pState == 1 and (wasP2 or wasDanger);
def earlyPressure = pState == 1 and !lightPressure;

# --- Directional Mapping (P2-red / P2-green) ---
def p2Color =
    if pState == 2 and bullBias and p2Danger then 1 else
    if pState == 2 and bearBias and p2Danger then -1 else 0;

############################################
# COMPATIBILITY LAYER FOR TSI (volState + exhaustionState)
############################################

def volState =
    if domeExpansion and AbsValue(domeROC) > domeSmooth * 0.20 then 0 else
    if domeExpansion then 1 else
    if !domeExpansion and !domeCompression then 2 else
    if domeCompression and AbsValue(domeROC) < domeSmooth * 0.10 then 3 else
    4;

input zExtreme = 2.5;
input zLate    = 1.5;
input zEarly   = 0.5;

def isExhausted = AbsValue(zScore) > zExtreme and zSlope < 0 and z2 < 0;
def isLateMove  = AbsValue(zScore) > zLate and zSlope <= 0;
def isNeutral   = AbsValue(zScore) between zEarly and zLate;
def isEarlyMove = AbsValue(zScore) < zEarly and zSlope > 0;
def isFresh     = zScore crosses above 0 or zScore crosses below 0;

def exhaustionState =
    if isExhausted then 0 else
    if isLateMove  then 1 else
    if isNeutral   then 2 else
    if isEarlyMove then 3 else
    if isFresh     then 4 else 2;

############################################
# INTERNAL OVERWATCH OUTPUTS
############################################

def Overwatch_PState      = pState;
def Overwatch_P2Danger    = if p2Danger then 1 else 0;
def Overwatch_P2Color     = p2Color;
def Overwatch_MicroState  = microState;
def Overwatch_BullBias    = bullBias;
def Overwatch_BearBias    = bearBias;

############################################
# NUMERIC ENUM TAGS (REQUIRED FOR TSI)
############################################

def priceValuationCode =
    if valueOpportunity then 8 else
    if cheapButExtended then 1 else
    if highQualityOnSale then 2 else
    if valueTrapRisk then 3 else
    if richValImproving then 4 else
    if speculativeGrowth then 5 else
    if cashFlowMachine then 6 else
    if longTermCandidate then 7 else
    0;

def narrativeCode =
    if cheapButExtended then 1 else
    if highQualityOnSale then 2 else
    if valueTrapRisk then 3 else
    if richValImproving then 4 else
    if speculativeGrowth then 5 else
    if cashFlowMachine then 6 else
    if longTermCandidate then 7 else
    0;

############################################
# TRADE SENTIMENT INDICATOR (TSI) v1.2
############################################

input wTrend      = 25;
input wValuation  = 20;
input wGrowth     = 15;
input wVolatility = 15;
input wExhaustion = 10;
input wNarrative  = 15;

def totalWeight =
    wTrend + wValuation + wGrowth +
    wVolatility + wExhaustion + wNarrative;

def trendScore =
    if microState == 0 then 25 else
    if microState == 1 then 45 else
    if microState == 2 then 75 else
    if microState == 3 then 90 else
    50;

def tsiValuationScore =
    if valuationScore == 3 then 80 else
    if valuationScore == 2 then 60 else
    if valuationScore == 1 then 35 else
    15;

def growthScore =
    if CAGR < 0 then 10 else
    if CAGR < 0.05 then 35 else
    if CAGR < 0.10 then 55 else
    if CAGR < 0.20 then 75 else
    90;

def volScore =
    if volState == 0 then 15 else
    if volState == 1 then 35 else
    if volState == 2 then 55 else
    if volState == 3 then 75 else
    if volState == 4 then 90 else
    50;

def exhaustionScore =
    if exhaustionState == 0 then 15 else
    if exhaustionState == 1 then 35 else
    if exhaustionState == 2 then 55 else
    if exhaustionState == 3 then 75 else
    if exhaustionState == 4 then 90 else
    50;

def tsiNarrativeScore =
    if narrativeCode == 1 then 35 else
    if narrativeCode == 2 then 85 else
    if narrativeCode == 3 then 15 else
    if narrativeCode == 4 then 65 else
    if narrativeCode == 5 then 20 else
    if narrativeCode == 6 then 75 else
    if narrativeCode == 7 then 90 else
    50;

def priceValuationScore =
    if priceValuationCode == 8 then 90 else
    if priceValuationCode == 1 then 35 else
    if priceValuationCode == 2 then 85 else
    if priceValuationCode == 3 then 15 else
    if priceValuationCode == 4 then 65 else
    if priceValuationCode == 5 then 20 else
    if priceValuationCode == 6 then 75 else
    if priceValuationCode == 7 then 90 else
    50;

def sentimentScore =
    (trendScore          * wTrend +
     tsiValuationScore   * wValuation +
     growthScore         * wGrowth +
     volScore            * wVolatility +
     exhaustionScore     * wExhaustion +
     tsiNarrativeScore   * (wNarrative * 0.5) +
     priceValuationScore * (wNarrative * 0.5)
    ) / totalWeight;

def sentimentClass =
    if sentimentScore < 30 then 0 else
    if sentimentScore < 50 then 1 else
    if sentimentScore < 70 then 2 else
    if sentimentScore < 85 then 3 else
    4;

AddLabel(1,
    "Sentiment: " + Round(sentimentScore, 0),
    if sentimentClass == 0 then Color.RED
    else if sentimentClass == 1 then Color.DARK_ORANGE
    else if sentimentClass == 2 then Color.YELLOW
    else if sentimentClass == 3 then Color.GREEN
    else Color.CYAN,size = FontSize.Medium
);

AddLabel(1,
    if sentimentClass == 0 then "Avoid"
    else if sentimentClass == 1 then "High Risk"
    else if sentimentClass == 2 then "Tradeable"
    else if sentimentClass == 3 then "Strong Candidate"
    else "High-Quality Opportunity",
    Color.WHITE,size = FontSize.Medium
);


############################################
# BEHAVIOR NARRATIVE (OVERWATCH ENVIRONMENT)
############################################

def behaviorNarrative =
    if microState == 3 then 3 else              # Blowoff Risk (highest priority)
    if exhaustionState == 0 then 1 else         # Exhausted Move
    if exhaustionState == 4 then 2 else         # Fresh Move
    if volState == 0 then 5 else                # High Volatility / Turbulent
    if volState == 4 then 6 else                # Controlled Compression
    if microState == 0 then 4 else              # Compression / Base Building
    0;                                          # Neutral Environment

AddLabel(1,
    if behaviorNarrative == 1 then "Exhausted Move" else
    if behaviorNarrative == 2 then "Fresh Move" else
    if behaviorNarrative == 3 then "Blowoff Risk" else
    if behaviorNarrative == 4 then "Compression" else
    if behaviorNarrative == 5 then "High Volatility" else
    if behaviorNarrative == 6 then "Controlled Compression" else
    "Neutral Environment",
    Color.LIGHT_GRAY
);

############################################
# TRADE ADVICE (OVERWATCH COMBINATIONS)
############################################

# --- 1. Blowoff Risk — Do Not Add ---
def cueBlowoff =
    microState == 3 and
    exhaustionState <= 1;   # blowoff or late move

AddLabel(cueBlowoff,
    "Blowoff Risk — Do Not Add",
    Color.RED
);

# --- 2. Exhausted Move — Avoid New Entries ---
def cueExhausted =
    exhaustionState == 0 and
    microState != 3;

AddLabel(cueExhausted,
    "Exhausted Move — Avoid New Entries",
    Color.DARK_RED
);

# --- 3. High Volatility — Reduce Size ---
def cueHighVol =
    volState == 0 and
    exhaustionState != 4 and
    microState != 0;

AddLabel(cueHighVol,
    "High Volatility — Reduce Size",
    Color.ORANGE
);

# --- 4. Early Trend Starting ---
def cueEarlyTrend =
    exhaustionState == 4 and          # fresh move
    Overwatch_P2Color == 1 and        # P2-Green
    (microState == 1 or microState == 2) and
    (volState == 1 or volState == 2);

AddLabel(cueEarlyTrend,
    "Early Trend Starting",
    Color.CYAN
);

# --- 5. Accumulate / Add on Dips ---
def cueAccumulate =
    behaviorNarrative == 6 and        # Controlled Compression
    Overwatch_P2Color == 1 and        # P2-Green
    exhaustionState != 0 and          # not exhausted
    microState != 3;                  # not blowoff

AddLabel(cueAccumulate,
    "Accumulate / Add on Dips",
    Color.GREEN
);

# --- 6. Wait for Pullback ---
def cueWaitPullback =
    Overwatch_P2Color == 1 and        # P2-Green
    exhaustionState == 1 and          # late move
    (microState == 2 or microState == 3);

AddLabel(cueWaitPullback,
    "Wait for Pullback",
    Color.YELLOW
);

# --- 7. Base Building — Watch for Breakout ---
def cueBaseBuilding =
    microState == 0 and               # compression coil
    (volState == 3 or volState == 4) and
    exhaustionState == 2;
AddLabel(cueBaseBuilding,
    "Compression Base — Breakout Possible",
    Color.LIGHT_GRAY
);


# --- 8. Neutral — No Clear Edge ---
def cueNeutral =
    !cueBlowoff and
    !cueExhausted and
    !cueHighVol and
    !cueEarlyTrend and
    !cueAccumulate and
    !cueWaitPullback and
    !cueBaseBuilding;

AddLabel(cueNeutral,
    "Neutral — No Clear Edge",
    Color.GRAY
);

##      Trade Labels ###################

############################################
# SECTOR-AWARE RETAIL CUES (MODERATE)
############################################

# --- 1. Strong Stock in Strong Sector ---
def cueStrongStrong =
    strengthCode == 1 and
    alignmentCode == 1 and
    confidence > 0.40;

AddLabel(cueStrongStrong,
    "Strong Stock & Sector — Follow-Through Likely",
    Color.GREEN
);

# --- 2. Strong Stock in Weak Sector ---
def cueStrongWeak =
    strengthCode == -1 and
    alignmentCode == 2 and
    confidence > 0.30;

AddLabel(cueStrongWeak,
    "Strong Stock in Weak Sector — Reduce Size / Expect Chop",
    Color.DARK_GREEN
);

# --- 3. Laggard in Strong Sector ---
def cueLaggardStrong =
    strengthCode == 1 and
    alignmentCode == 3 and
    confidence > 0.30;

AddLabel(cueLaggardStrong,
    "Laggard in Strong Sector — Avoid Until Strength Improves",
    Color.ORANGE
);

# --- 4. Laggard in Weak Sector ---
def cueLaggardWeak =
    strengthCode == -1 and
    alignmentCode == 4 and
    confidence > 0.25;

AddLabel(cueLaggardWeak,
    "Laggard in Weak Sector — No Tailwind",
    Color.RED
);

# --- 5. Sector Drift / Low Confidence ---
def cueSectorDrift =
    trendCode == 0 and
    confidence < 0.35;

AddLabel(cueSectorDrift,
    "Sector Drift — Expect Low Follow-Through",
    Color.GRAY
);

# --- 6. Sector Tailwind ---
def cueTailwind =
    trendCode > 0 and
    strengthCode == 1 and
    confidence > 0.50;

AddLabel(cueTailwind,
    "Sector Tailwind — Moves Have Support",
    Color.GREEN
);

# --- 7. Sector Headwind ---
def cueHeadwind =
    trendCode < 0 and
    strengthCode == -1 and
    confidence > 0.50;

AddLabel(cueHeadwind,
    "Sector Headwind — Expect Resistance",
    Color.RED
);

# --- 8. Neutral Sector Context ---
def cueSectorNeutral =
    !cueStrongStrong and
    !cueStrongWeak and
    !cueLaggardStrong and
    !cueLaggardWeak and
    !cueSectorDrift and
    !cueTailwind and
    !cueHeadwind;

AddLabel(cueSectorNeutral,
    "Sector Neutral — No Major Influence",
    Color.LIGHT_GRAY
);
 
Last edited by a moderator:
📌 What to Look For — Quick Operator Cheat Sheet

1. Environment (Market State)


These are the conditions you’re trading inside. Before anything else, identify the environment.

  • Trend posture — rising, falling, or transitioning
  • Volatility regime — calm, expanding, or chaotic
  • Pressure bias — buyers or sellers controlling the tape
  • Energy state — building, releasing, or exhausted
  • Context alignment — does the environment support continuation or reversal
If the environment is unclear, nothing else matters.

2. Structure (Where You Are)


This is the map. Structure tells you the location of the move.

  • Trend integrity — clean trend, broken trend, or trend under stress
  • Key zones — support, resistance, mid‑zones, liquidity shelves
  • Slope behavior — flattening, steepening, or curling
  • Compression vs expansion — tightening coils or wide swings
  • Breaks and retests — clean, sloppy, or failed
Structure defines the battlefield.

3. Behavior (What Price Is Doing Right Now)


This is the heartbeat. Behavior tells you the quality of the move.

  • Momentum quality — strong, weak, fading, or erratic
  • Exhaustion signals — wicks, failed pushes, volume collapse
  • Aggression — decisive candles vs hesitant probes
  • Follow‑through — continuation or immediate rejection
  • MicroState shifts — tightening, stalling, or accelerating
Behavior reveals the truth of the moment.

4. Flow (Pressure + Overwatch)


This is the intent behind the move.

  • Pressure direction — who is actually pushing
  • Pressure strength — light, moderate, or heavy
  • Overwatch cues — strength building, weakness building, or instability
  • Imbalance — clean directional flow or messy two‑way fighting
  • Energy transfer — pressure → behavior → structure
Flow tells you who is winning the fight.

5. Timing (When It Matters)


This is where traders separate themselves.

  • Fresh moves — early in the sequence
  • Late moves — exhaustion risk
  • Retests — confirmation or failure
  • Breakouts — clean or forced
  • Reversals — early signal or late chase
Timing determines risk.

6. Alignment (The Green Light)


You’re looking for agreement across layers:

  • Environment supports the idea
  • Structure provides the location
  • Behavior confirms the moment
  • Flow shows intent
  • Timing reduces risk
When all five align, you have clarity.
 

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

Similar threads

Not the exact question you're looking for?

Start a new thread and receive assistance from our community.

87k+ Posts
744 Online
Create Post

Similar threads

Similar threads

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