TMO HH Scan

rewardiaz

Active member
VIP
Hey everyone, could someone help me transform this code into a scan? I’m basically looking for stocks that have printed a higher high (HH). @antwerks any ideas?

Python:
# TMO
def TMO_length = 14;
def TMO_calcLength = 5;
def TMO_smoothLength = 3;
def pivotBars = 3;
def na = Double.NaN;

script FindPivot {
  input src     = close;
  input bars    = 5;       # lookback window
  input isHigh  = yes;     # yes = high, no = low

  def bn = BarNumber();
  def na = Double.NaN;

  # check that src is extreme vs. the last 'length' bars
  def isExtreme = fold i = 1 to bars
                   with ok = yes
                   while ok
                   do if isHigh
                      then src > GetValue(src, -i)
                      else src < GetValue(src, -i);

  def pivot =
      if bn > bars
         && isExtreme
         && ( if isHigh
               then src == Highest(src, bars)
               else src == Lowest(src, bars))
      then src
      else na;

  plot pPivot = pivot;
}

# ##################################################
# True Momentum Oscilator
def TMO_os = -Round(TMO_length * 0.7);
def TMO_ob = Round(TMO_length * 0.7);

def TMO_Data =
    fold i = 0 to TMO_length
    with acc
    do acc + if close > GetValue(open, i) then 1
    else if close < GetValue(open, i) then -1
    else 0;

def EMA5 = ExpAverage(close, TMO_calcLength);
def TMO_main = ExpAverage(EMA5, TMO_smoothLength);

def crossedUpOB   = TMO_main crosses above TMO_ob;
def crossedDownOB = TMO_main crosses below TMO_ob;

rec inOBZone = CompoundValue(1,
    if crossedUpOB then 1
    else if crossedDownOB then 0
    else inOBZone[1],
0);

def pivotOffset = Floor(pivotBars / 2);
def rawHighPivot = FindPivot(src=TMO_main, bars=pivotBars, isHigh=yes).pPivot;

# only accept highs in overbought, lows in oversold
def lastHighVal= if inOBZone then rawHighPivot else na;

# When a fresh pivot occurs, shift last→prev then capture new pivot
def isNewHighPivot = !IsNaN(lastHighVal) && IsNaN(lastHighVal[1]);

# high data
rec rlastHighVal = if isNewHighPivot then lastHighVal else rlastHighVal[1];
rec prevHighVal = if isNewHighPivot then rlastHighVal[1] else prevHighVal[1];

# High pivots (higher‐high or lower‐high)
def TMO_HH = lastHighVal > prevHighVal;

plot scan = (TMO_HH within 7 bars);
 
Solution
I don’t do TradingView conversions, and I don’t debug AI-generated code. It is a hard rule, like gravity or “don’t microwave aluminum.”

Much admiration that @halcyonguy can wrangle AI code and make it purr.
Me? I open AI code and immediately question my life choices. 😵

But this project was intriguing. Here is the question:
If TMO has broached the overbought zone; how do you know if momentum will continue or
if the trend is dead.

@rewardiaz appears to have found the answer:
If the Overbought High is higher than the previous Overbought High (green dot); it will continue to retrace higher.
Otherwise, the trend is dead.
Given that three of my four current open trades have a green dot; here is hoping that he is...
I don’t do TradingView conversions, and I don’t debug AI-generated code. It is a hard rule, like gravity or “don’t microwave aluminum.”

Much admiration that @halcyonguy can wrangle AI code and make it purr.
Me? I open AI code and immediately question my life choices. 😵

But this project was intriguing. Here is the question:
If TMO has broached the overbought zone; how do you know if momentum will continue or
if the trend is dead.

@rewardiaz appears to have found the answer:
If the Overbought High is higher than the previous Overbought High (green dot); it will continue to retrace higher.
Otherwise, the trend is dead.
Given that three of my four current open trades have a green dot; here is hoping that he is correct! ;)
b9mmffp.png


TMO High vs Previous High code​

With these changes
1. Used Mobius’s original TMO (the classic, non-AI flavored)
2. Aimed straight at the goal. Anything wandering off-task got vaporized
3. AI loves deprecated syntax. Sure, it runs today, but tomorrow, Schwab can turn it into a historical artifact.
rec function’s retirement party:
https://toslc.thinkorswim.com/center/reference/thinkScript/Reserved-Words/rec
&& didn't get a retirement party. It went away with a whisper.

This scan looks for stocks whose current TMO High is greater than their previous TMO High. It’s run against a pre-filtered list of stocks identified by the script in the Scan In field. By referencing this script:
https://usethinkscript.com/threads/...ock-corral-via-option-volume-and-delta.21634/ , the scan focuses only on stocks most likely to move today.
DRalnKS.png


Here is the chart study. Page down further for the scanner script
Ruby:
# TMO ((T)rue (M)omentum (O)scillator)
# Mobius
# V01.05.2018
# hint: TMO calculates momentum using the delta of price. Giving a much better picture of trend, tend reversals and divergence than momentum oscillators using price.

declare Lower;

input length = 14;
input calcLength = 5;
input smoothLength = 3;

def o = open;
def c = close;
def data = fold i = 0 to length
           with s
           do s + (if c > getValue(o, i)
                   then 1
                   else if c < getValue(o, i)
                        then - 1
                        else 0);
def EMA5 = ExpAverage(data, calcLength);
plot Main = ExpAverage(EMA5, smoothLength);
plot Signal = ExpAverage(Main, smoothLength);
     Main.AssignValueColor(if Main > Signal
                           then color.green
                           else color.red);
     Signal.AssignValueColor(if Main > Signal
                             then color.green
                             else color.red);
     Signal.HideBubble();
     Signal.HideTitle();
addCloud(Main, Signal, color.green, color.red);
plot zero = if isNaN(c) then double.nan else 0;
     zero.SetDefaultColor(Color.gray);
     zero.hideBubble();
     zero.hideTitle();
plot ob = if isNaN(c) then double.nan else round(length * .7);
     ob.SetDefaultColor(Color.gray);
     ob.HideBubble();
     ob.HideTitle();
plot os = if isNaN(c) then double.nan else -round(length * .7);
     os.SetDefaultColor(Color.gray);
     os.HideBubble();
     os.HideTitle();
addCloud(ob, length, color.light_red, color.light_red, no);
addCloud(-length, os, color.light_green, color.light_green);
# End Code TMO


# scanner logic
input pivotBars = 3;
script FindHighPivot {
    input src  = close; input bars = 5;
    def isExtreme = fold i = 1 to bars
                   with ok = yes
                   while ok
                   do src > GetValue(src, -i);
    def pivot = if isExtreme and (src == Highest(src, bars)) then src else Double.NaN;
    plot pPivot = pivot;
}


def rawHighPivot = FindHighPivot(src=main, bars=pivotBars).pPivot;
def highPivotVal = if rawHighPivot>ob then rawHighPivot else Double.NaN;


def isNewHighPivot = !IsNaN(highPivotVal) and IsNaN(highPivotVal[1]);
def rlastHighVal = if isNewHighPivot then highPivotVal else rlastHighVal[1];
def prevHighVal = if isNewHighPivot then rlastHighVal[1] else prevHighVal[1];

plot highs = if main == rlastHighVal or main == prevHighVal then main else double.NaN;
highs.SetPaintingStrategy(PaintingStrategy.LINE_VS_POINTS);
highs.AssignValueColor(if rlastHighVal > prevHighVal then color.green else color.orange);
highs.SetLineWeight(3);


AddLabel(yes, "Last Pivot High: " +round(rlastHighVal,1) +" | Previous Pivot High: " +round(prevHighVal,1),
if rlastHighVal > prevHighVal then color.green else color.orange);

Here is the Scan Hacker Code:
Ruby:
# TMO ((T)rue (M)omentum (O)scillator)
# High vs Previous High Scanner Only

input length = 14;
input calcLength = 5;
input smoothLength = 3;

def o = open;
def c = close;
def data = fold i = 0 to length
           with s
           do s + (if c > getValue(o, i)
                   then 1
                   else if c < getValue(o, i)
                        then - 1
                        else 0);
def EMA5 = ExpAverage(data, calcLength);
def Main = ExpAverage(EMA5, smoothLength);
def ob = if isNaN(c) then double.nan else round(length * .7);
def os = if isNaN(c) then double.nan else -round(length * .7);

# scanner logic
input pivotBars = 3;
script FindHighPivot {
    input src  = close; input bars = 5;
    def isExtreme = fold i = 1 to bars
                   with ok = yes
                   while ok
                   do src > GetValue(src, -i);
    def pivot = if isExtreme and (src == Highest(src, bars)) then src else Double.NaN;
    plot pPivot = pivot;
}

def rawHighPivot = FindHighPivot(src=main, bars=pivotBars).pPivot;
def highPivotVal = if rawHighPivot>ob then rawHighPivot else Double.NaN;


def isNewHighPivot = !IsNaN(highPivotVal) and IsNaN(highPivotVal[1]);
def rlastHighVal = if isNewHighPivot then highPivotVal else rlastHighVal[1];
def prevHighVal = if isNewHighPivot then rlastHighVal[1] else prevHighVal[1];


plot scan = rlastHighVal > prevHighVal;
 
Last edited:
Solution
Thank you, Merry, I appreciate everyone’s time. ‘&&’ is just a personal habit, and the same goes for how I name my variables. Thanks again.

What I’m really trying to identify is when TMO prints a higher high against a previous higher high while in the overbought zone. In your example, the peaks labeled 2, 3, 7, and 9 aren’t relevant. I want to compare 1 vs. 4 (showing extra strength), then 4 vs. 5 (clear weakness), then 6 vs. 8 (weakness), and now 10 looks promising. These are just observations, but I’ve seen similar behavior across stocks and I’m wondering if a scan can capture that. My current code only tells me when we have an HH under this condition.


image.png
 
Last edited:
What I’m really trying to identify is when TMO prints a higher high against a previous higher high while in the overbought zone.

Actually, that is the way I originally was going with it.
Just a simple High > OB

But given that you put in this whole run-around to find any high; I went with it.
def crossedUpOB = main crosses above ob;
def crossedDownOS = main crosses below os;

def inOBZone = CompoundValue(1,
if crossedUpOB then 1 else
if crossedDownOS then 0 else inOBZone[1], 0)

Okay, changed the above to the below:
rawHighPivot>ob
changes were incorporated into the above post:
https://usethinkscript.com/threads/tmo-hh-scan.21805/#post-157955
 
Last edited:
My take
1763101666418.png

1763103472231.png


comparison of two codes:
FsJEx8S.png

https://tos.mx/!pBH8Xrfd
Code:
# ==============================================================
# TMO Higher High Indicator
# Converts the TMO HH scan into a chart study with signals
# rewardiaz and antwerks ==============================================================

declare lower;

input TMO_length = 14;
input TMO_calcLength = 5;
input TMO_smoothLength = 3;
input pivotBars = 3;

def na = Double.NaN;

# --------------------------------------------------------------
# Pivot Finder (original script)
# --------------------------------------------------------------
script FindPivot {
    input src = close;
    input bars = 5;
    input isHigh = yes;

    def bn = BarNumber();
    def na = Double.NaN;

    def isExtreme =
        fold i = 1 to bars
        with ok = yes
        while ok
        do if isHigh
            then src > GetValue(src, -i)
            else src < GetValue(src, -i);

    def pivot =
        if bn > bars and isExtreme and
           (if isHigh
               then src == Highest(src, bars)
               else src == Lowest(src, bars))
        then src
        else na;

    plot pPivot = pivot;
}

# --------------------------------------------------------------
# True Momentum Oscillator (TMO)
# --------------------------------------------------------------

def TMO_os = -Round(TMO_length * 0.7);
def TMO_ob =  Round(TMO_length * 0.7);

def TMO_Data =
    fold i = 0 to TMO_length
    with acc
    do acc +
        (if close > GetValue(open, i) then 1
         else if close < GetValue(open, i) then -1
         else 0);

def EMA5 = ExpAverage(TMO_Data, TMO_calcLength);
def TMO_main = ExpAverage(EMA5, TMO_smoothLength);

# OB/OS zone tracking
def crossedUpOB   = TMO_main crosses above TMO_ob;
def crossedDownOB = TMO_main crosses below TMO_ob;

rec inOBZone =
    CompoundValue(1,
        if crossedUpOB then 1
        else if crossedDownOB then 0
        else inOBZone[1],
    0);

# --------------------------------------------------------------
# Pivot High Logic (using your original routine)
# --------------------------------------------------------------
def rawHighPivot = FindPivot(TMO_main, pivotBars, yes).pPivot;

def lastHighVal = if inOBZone then rawHighPivot else na;

def isNewHighPivot = !IsNaN(lastHighVal) and IsNaN(lastHighVal[1]);

rec rlastHighVal =
    if isNewHighPivot then lastHighVal else rlastHighVal[1];

rec prevHighVal =
    if isNewHighPivot then rlastHighVal[1] else prevHighVal[1];

# Higher High condition
def TMO_HH = lastHighVal > prevHighVal;

# --------------------------------------------------------------
# Indicator Plots
# --------------------------------------------------------------

plot TMO = TMO_main;
TMO.SetDefaultColor(Color.CYAN);

plot OB = TMO_ob;
OB.SetDefaultColor(Color.RED);
OB.SetStyle(Curve.SHORT_DASH);

plot OS = TMO_os;
OS.SetDefaultColor(Color.GREEN);
OS.SetStyle(Curve.SHORT_DASH);

# The pivot points on TMO
plot HighPivotPlot = lastHighVal;
HighPivotPlot.SetPaintingStrategy(PaintingStrategy.POINTS);
HighPivotPlot.SetDefaultColor(Color.YELLOW);
HighPivotPlot.SetLineWeight(3);

# Signal arrow when a Higher High is detected
plot HH_Signal = if isNewHighPivot and TMO_HH then TMO_main else na;
HH_Signal.SetPaintingStrategy(PaintingStrategy.ARROW_UP);
HH_Signal.SetDefaultColor(Color.LIGHT_GREEN);
HH_Signal.SetLineWeight(3);

# --------------------------------------------------------------
# Labels
# --------------------------------------------------------------

AddLabel(TMO_HH, "TMO Higher High", Color.GREEN);
AddLabel(!TMO_HH, "No Higher High", Color.GRAY);

# This allows chart visibility rather than scanning
plot IndicatorSignal = TMO_HH;
IndicatorSignal.Hide();
 
Last edited by a moderator:

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
703 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