testing Mobius ORB w/ Volume Profile In ThinkOrSwim

snoopydoopy

New member
VIP
Mobius ORB w/ Volume Profile and stats to test his theory​

Hi everyone! First time posting an indicator here so hopefully I do this correctly and coherently. Firstly I just want to say it right up front this is just an indicator, I am still working through how I want to use this as an actual strategy. There is also no buy or sell signals, this is an ORB indicator that tests out Mobius theory on the day bias has a 60 - 70% chance of being accurate. I also want to say that I am not by any means a coder. My extent is I can read some code and I know what I need to edit to potentially get something to work but I can't write code from scratch so a lot of this code is built from ChatGPT / Claude that I then edited to make work, so there is a very good chance this isn't written as efficiently as possible and could probably use some touchups.

So I have been messing around with building an ORB indicator based around Mobius's original ORB script. I really like the idea behind the ORB so I wanted to look into it more. However, the issue with the script painting lines a day or two ahead so they weren't on the day needed rendered it unusable but then I came across one that MerryDay posted as a scan which I found interesting (https://usethinkscript.com/threads/opening-range-breakout-orb-scanner-for-thinkorswim.68/). So I took this and went digging in JQs archives to read more about the ORB. I really like the ORB indicator with volume profile which I really liked but it didn't have actual ORB lines just VAH and VAL so I did some combining of the ORB and Volume Profile to make my own.

Next we come to the actual theory behind ORB and the edge that Mobius says that it has:

"Why it works: Overnight orders accumulate. Those orders being placed during the first 15 minutes of Regular Trading Hours combined with the typical high volume in the first 30 minutes of trading make this the most volatile trading period of the day. Regularly released reports during the first 30 minutes of trading add to the volatility and effect the days direction. FYI the color of Probable close direction points are statistically accurate between 60% and 70% of the time. Trading against the direction of the ORB's Day Filtered Direction should be considered counter trend trades. You have just under a 52% probability that a DAILY bar will close green. So a 60% to 70% probability is a nice edge."

The 60 - 70% accuracy sounded intriguing so I went to work coding that out with some labels. Here is how I did that.

(Firstly this is all based on using a 5 minute chart and I believe it is actually hard coded to only be able to use a 5 minute timeframe. If someone who actually knows code can help open it up to be able to use other timeframes that could be useful.)

The actual theory is that 60-70% of the time, when we find the days direction bias the stock will close the day with that same bias (either above or below the mean)

  1. The yellow dashed line represents the mean line which is based on the first 5 minute candle of the day (From Mobius: The yellow dashed line is the Day Filter Line and is used to determine the trend direction for the day. The dominant time spent above or below this line during the Opening Range Period typically determines the days trend. Green points indicate a close at EOD above the yellow line. Red Points a close below the yellow line. Yellow points a neutral or balanced day, close Between the Opening Range Extremes and often very near the Day Filter Line. The Opening Range is plotted with a green and red dashed line.)
  2. I didn't like how the red, green and yellow dots looked it took a lot of space on the 7th candle of the day so I changed it to Cyan and Magenta wedges on the 6th candle of the day (which is the 9:55 candle but it closes at 10 so we use that candle to get the bias). Cyan wedge means we have an up bias for the day because the 6th candle closed above the mean line. A magenta wedge means we have a down bias for the day because the candle closed below the mean line.
  3. The next part is figuring out if the stock closed the day above or below the mean line. A cyan wedge on the 78th candle of the day (the last candle of the day) means we closed the day above the mean line. A magenta wedge on that 78th candle means we closed the day below the mean line. If we have a cyan up bias wedge on the 6th candle of the day to start the day and a cyan wedge on the 78th candle to end the day that means that day met the conditions of the theory. If we have a magenta wedge down bias on the 6th candle and a magenta wedge on the 78th candle to end the day that also means we met the conditions of the theory.
  4. This is then represented by the "Accuracy: " label on the chart, it looks how many times the conditions of the theory of the two wedges being the same color are met on whatever number of days back you want to look at regardless of up or down bias. (on a 5 minute chart the furthest you can go back is 180 days so my screenshots will be with 180 days back in mind)

Here are some results.

SPY 180 day 5 Minute Aggregation - Accuracy 60.69%

1736737962484.png


NVDA 180 day 5 minute Aggregation - Accuracy 72.73%

1736738727403.png



Meta 180 days 5 minute - Accuracy: 66.74%

1736738790316.png


Please note these accuracy numbers are just stats for the ORB to test the theory out, these aren't win rates or anything as there are no buy / sell signals at the moment. The are numbers to know the statistical chance of Mobius theory to find good stocks to trade and build a theory around the accuracy knowledge.


Here is what the chart actually looks like on a 5 day timeframe so you can see the actual functionality:

1736738906171.png


So the yellow dashed line is the mean for the day
Red dashed line is the ORL
Green dashed line is the ORH.
Magenta horizontal line is the POC for the volume profile and the two white horizontal lines are the VAL and VAH for the Volume profile.


You may have noticed some other labels on the chart so let me break them down for you:

1736739020806.png


1. Bias: This is a dynamic intraday label and will show you the bias for the day as a label
2. This is a dynamic intraday label that shows where the candles currently are for the given stock comparison to the ORB lines as well as in relation to the volume profile lines. The options on that label are
CROSSING ORH! VP: " + if close > POC then "Above POC" else "Below POC"
" CROSSING ORL! VP: " + if close > POC then "Above POC" else "Below POC"
"Above ORH"
" Below ORL "
" Inside OR "
3. Accuracy: As discussed how accurate a given stock is at meeting the theory of the ORB.
4. Inside OR closes: This is how often the stock closes inside the actual Opening range (in between ORH and ORL)
5. Up Bias above ORH Success: This is similar to Accuracy but broken down a little further, this is how often if we have an up bias day the stock closes above the opening range high as opposed to closing in the opening range but above the mean or below the mean, etc.
6. Down bias below ORL success: same thing as #5
7. Total bias Above/below ORH/ORL success: I realize this is a long name lol I didn't know what else to call it but it is just the totals between #5 and #6

Once again I want to reiterate this is just an indicator, I am still working through how I actually want to trade with it, the 60-70% accuracy looks promising but you could do something like trading a bounce back to the mean or a breakout and retest, etc. there is a lot of ways to trade this. I will update the posting as I learn more and get a better understanding of how I am going to try and trade this method.

Edit #1 1/13/2025 - Finally figured out how to toggle on and off the volume profile histogram but it will still leave the POC and VAH/VAL. Makes it a little easier to read

Here is the TOS share link: http://tos.mx/!BnIbRRyZ

Code below:

Code:
# Combined Opening Range Breakout with Volume Profile
# Original ORB by KumoBob, Modified by Clayburgs
# Volume Profile integration added 2025
# Merged with "6th-candle dot" + corrected accuracy label logic

declare upper;

def na = Double.NaN;

############### Volume Profile Section ##############
def TS = TickSize();
def t = getTime() crosses RegularTradingStart(getYYYYMMDD()) 
        or 
        getTime() crosses above RegularTradingStart(getYYYYMMDD()) + 
                                aggregationPeriod.Thirty_Min;

profile vol = VolumeProfile(getSymbol(), TS, t, 0, 4, 68);

input showClouds = yes;  # Add this line after other inputs

def pc = if IsNaN(vol.GetPointOfControl()) 
         then pc[1]  
         else vol.GetPointOfControl();
def hVA = if IsNaN(vol.GetHighestValueArea()) 
          then hVA[1]  
          else vol.GetHighestValueArea();
def lVA = if IsNaN(vol.GetLowestValueArea())  
          then lVA[1]  
          else vol.GetLowestValueArea();

# Volume Profile Plots
plot POC = Round(pc / TS, 0) * TS;
POC.SetDefaultColor(Color.Magenta);
POC.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
POC.SetLineWeight(2);

plot VAHigh = Round(hVA / TS, 0) * TS;
VAHigh.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
VAHigh.SetDefaultColor(Color.white);
VAHigh.SetLineWeight(1);

plot VALow = Round(lVA / TS, 0) * TS;
VALow.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
VALow.SetDefaultColor(Color.white);
VALow.SetLineWeight(1);

input showVolumeHistogram = yes;
DefineGlobalColor("Transparent", CreateColor(0, 0, 0));

# Show volume profile histogram
vol.Show(
    if showVolumeHistogram then Color.CYAN else GlobalColor("Transparent"),
    if showVolumeHistogram then Color.GRAY else GlobalColor("Transparent"),
    if showVolumeHistogram then Color.CYAN else GlobalColor("Transparent"),
    if showVolumeHistogram then 15 else 0
);

############### Directional Day Filter Line (first 5min OR) ##############
input ORBegin = 0930;
input OREnd   = 0935;
input ShowTodayOnly = { default "No", "Yes"};
def s = ShowTodayOnly;

# Create logic for OR definition: 1 if between first 5 minutes
def ORActive = if secondsTillTime(OREnd) > 0 and secondsFromTime(ORBegin) >= 0 
               then 1 
               else 0;

def today = if s == 0 
               or (getDay() == getLastDay() and secondsFromTime(ORBegin) >= 0) 
            then 1 
            else 0;

# Track OR High:
rec ORHigh = if ORHigh[1] == 0 or (ORActive[1] == 0 and ORActive == 1) 
             then high 
             else if ORActive and high > ORHigh[1] 
                  then high 
                  else ORHigh[1];
# Track OR Low:
rec ORLow = if ORLow[1] == 0 or (ORActive[1] == 0 and ORActive == 1) 
            then low 
            else if ORActive and low < ORLow[1] 
                 then low 
                 else ORLow[1];

def ORWidth = ORHigh - ORLow;

# Middle of the first 5min OR:
def firstORMean = (ORHigh + ORLow) / 2;

def ORHA = if ORActive or today < 1 then na else ORHigh;
def ORLA = if ORActive or today < 1 then na else ORLow;
def O    = ORHA - (ORHA - ORLA) / 2;

plot ORL = if (O == 0) then na else O;
ORL.SetDefaultColor(Color.YELLOW);
ORL.SetStyle(Curve.LONG_DASH);
ORL.SetLineWeight(3);

################## 30-min OR lines #####################
input ORBegin2 = 0930;
input OREnd2   = 1000;

def ORActive2 = if secondsTillTime(OREnd2) > 0 and secondsFromTime(ORBegin2) >= 0 
                then 1 
                else 0;

rec ORHigh2 = if ORHigh2[1] == 0 or (ORActive2[1] == 0 and ORActive2 == 1) 
              then high 
              else if ORActive2 and high > ORHigh2[1] 
                   then high 
                   else ORHigh2[1];
rec ORLow2 = if ORLow2[1] == 0 or (ORActive2[1] == 0 and ORActive2 == 1) 
             then low 
             else if ORActive2 and low < ORLow2[1] 
                  then low 
                  else ORLow2[1];

plot ORH2 = if ORActive2 or today < 1 then na else ORHigh2;
plot ORL2 = if ORActive2 or today < 1 then na else ORLow2;

ORH2.SetDefaultColor(Color.LIGHT_GREEN);
ORH2.SetStyle(Curve.LONG_DASH);
ORH2.SetLineWeight(3);

ORL2.SetDefaultColor(Color.LIGHT_RED);
ORL2.SetStyle(Curve.LONG_DASH);
ORL2.SetLineWeight(3);

# Optionally, add a cloud
AddCloud(
    if showClouds then ORL  else na,
    if showClouds then ORH2 else na,
    Color.GREEN,
    Color.LIGHT_GREEN
);

AddCloud(
    if showClouds then ORL2 else na,
    if showClouds then ORL  else na,
    Color.RED,
    Color.LIGHT_RED
);

##################  (Remove or hide the "d1..d10" & "bd1..bd10" plots) ####################
# We simply comment them out or hide them to avoid the 7 dots and arrow spam.
# -- Original code omitted here for brevity --

##################  Volume Profile "Bias" label ##################
def Span   = (O - ORL2) / (ORH2 - ORL2);
def vpBias = if close > POC then 1 else if close < POC then -1 else 0;
rec colorState =
    if Span > 0.66 or (Span > 0.5 and vpBias > 0) then -1
    else if Span < 0.33 or (Span < 0.5 and vpBias < 0) then 1
    else 0;

AddLabel(
    yes,
    if colorState < 0 then
        " Bias: DOWNWARD (VP: " +
            if vpBias < 0 then "Confirmed" else "Mixed" + ")"
    else if colorState > 0 then
        " Bias: UPWARD (VP: " +
            if vpBias > 0 then "Confirmed" else "Mixed" + ")"
    else
        " Bias: NEUTRAL ",
    if colorState < 0 then Color.RED
    else if colorState > 0 then Color.GREEN
    else Color.YELLOW
);

##################  Inside/Above/Below OR label ##################
def crossingORH = close crosses ORH2;
def crossingORL = close crosses ORL2;
def nearORH = AbsValue(close - ORH2) <= (ORH2 * 0.0005); 
def nearORL = AbsValue(close - ORL2) <= (ORH2 * 0.0005);

AddLabel(
    yes,
    if nearORH then
        " CROSSING ORH! VP: " + if close > POC then "Above POC" else "Below POC"
    else if nearORL then
        " CROSSING ORL! VP: " + if close > POC then "Above POC" else "Below POC"
    else if close > ORH2 then
        "Above ORH"
    else if close < ORL2 then
        " Below ORL "
    else
        " Inside OR ",
    if nearORH then
        Color.CYAN
    else if nearORL then
        Color.PINK
    else if close > ORH2 then
        Color.GREEN
    else if close < ORL2 then
        Color.RED
    else
        Color.WHITE
);

##################  STATS LOGIC (time-based)  ##################
#   This part yields the final "Accuracy: X / Y" label
#   based on the candle at 9:55 and the candle at 15:55
# -------------------------------------------------------------
################################################################################
# BAR-COUNT BASED LOGIC
################################################################################

def newDay = GetDay() <> GetDay()[1];

# Only count bars in RTH (9:30 - 16:00 ET):
def isRTHbar = SecondsFromTime(0930) >= 0 and SecondsTillTime(1600) > 0;

# Count bars from the open each day:
rec dayBarCounter =
    if newDay and isRTHbar then 1
    else if isRTHbar and !newDay then dayBarCounter[1] + 1
    else dayBarCounter[1];

# The 6th 5-minute bar is effectively 9:55; the 78th bar is 15:55:
def barEndsAtThirtyMin = (dayBarCounter == 6);
def barEndsDay         = (dayBarCounter == 78);

################################################################################
# DETERMINE DIRECTIONS AT 9:55 & 15:55
################################################################################

rec directionAt30 =
    if newDay then
        Double.NaN
    else if barEndsAtThirtyMin then
        if close > firstORMean then 1 else -1
    else
        directionAt30[1];

rec directionAtClose =
    if newDay then
        Double.NaN
    else if barEndsDay then
        if close > firstORMean then 1 else -1
    else
        directionAtClose[1];

################################################################################
# ACCURACY STATS
################################################################################

# We only increment totalCount and hitCount at the final bar of each day (#78).
rec totalCount =
    if IsNaN(totalCount[1]) then 0
    else if barEndsDay then
        totalCount[1] + 1
    else
        totalCount[1];

rec hitCount =
    if IsNaN(hitCount[1]) then 0
    else if barEndsDay then
        hitCount[1] +
        (if directionAt30 == directionAtClose then 1 else 0)
    else
        hitCount[1];

def accuracy = if totalCount > 0 then hitCount / totalCount else 0;

AddLabel(
    yes,
    " Accuracy: "
        + hitCount
        + " / "
        + totalCount
        + "  ("
        + AsPercent(accuracy)
        + ")" + "  ",
    if accuracy >= 0.5 then Color.GREEN else Color.RED
);

################################################################################
# 4)  Boolean Wedges at 6th bar & final bar
################################################################################

# -- 6th bar wedge(s) --
plot wedgeUp30 =
    if barEndsAtThirtyMin and directionAt30 == 1
    then high
    else Double.NaN;
wedgeUp30.SetPaintingStrategy(PaintingStrategy.BOOLEAN_WEDGE_UP);
wedgeUp30.SetDefaultColor(Color.CYAN);
wedgeUp30.SetLineWeight(3);

plot wedgeDown30 =
    if barEndsAtThirtyMin and directionAt30 == -1
    then low
    else Double.NaN;
wedgeDown30.SetPaintingStrategy(PaintingStrategy.BOOLEAN_WEDGE_DOWN);
wedgeDown30.SetDefaultColor(Color.MAGENTA);
wedgeDown30.SetLineWeight(3);


# -- Final bar wedge(s) --
plot wedgeUpFinal =
    if barEndsDay and directionAtClose == 1
    then high
    else Double.NaN;
wedgeUpFinal.SetPaintingStrategy(PaintingStrategy.BOOLEAN_WEDGE_UP);
wedgeUpFinal.SetDefaultColor(Color.CYAN);
wedgeUpFinal.SetLineWeight(3);

plot wedgeDownFinal =
    if barEndsDay and directionAtClose == -1
    then low
    else Double.NaN;
wedgeDownFinal.SetPaintingStrategy(PaintingStrategy.BOOLEAN_WEDGE_DOWN);
wedgeDownFinal.SetDefaultColor(Color.MAGENTA);
wedgeDownFinal.SetLineWeight(3);

# Add these variables after the existing stats logic section:
# Track inside OR closes at end of day 
rec insideORCloseCount = 
    if IsNaN(insideORCloseCount[1]) then 0
    else if barEndsDay then
        if close > ORL2 and close < ORH2 then
            insideORCloseCount[1] + 1
        else
            insideORCloseCount[1]
    else
        insideORCloseCount[1];

def insideORPercentage = if totalCount > 0 then insideORCloseCount / totalCount else 0;

AddLabel(
    yes,
    " Inside OR Closes: " + 
        insideORCloseCount + 
        " / " + 
        totalCount + 
        "  (" + 
        AsPercent(insideORPercentage) + 
        ")" + "  ",
    Color.WHITE
);

# Add these variables after the existing stats logic section:

# Track up bias (cyan wedge) success
rec upBiasCount =
    if IsNaN(upBiasCount[1]) then 0
    else if barEndsDay then
        if directionAt30[1] == 1 then
            upBiasCount[1] + 1
        else
            upBiasCount[1]
    else
        upBiasCount[1];

rec upBiasHits =
    if IsNaN(upBiasHits[1]) then 0
    else if barEndsDay then
        if directionAt30[1] == 1 and close > ORH2 then
            upBiasHits[1] + 1
        else
            upBiasHits[1]
    else
        upBiasHits[1];

# Track down bias (pink wedge) success
rec downBiasCount =
    if IsNaN(downBiasCount[1]) then 0
    else if barEndsDay then
        if directionAt30[1] == -1 then
            downBiasCount[1] + 1
        else
            downBiasCount[1]
    else
        downBiasCount[1];

rec downBiasHits =
    if IsNaN(downBiasHits[1]) then 0
    else if barEndsDay then
        if directionAt30[1] == -1 and close < ORL2 then
            downBiasHits[1] + 1
        else
            downBiasHits[1]
    else
        downBiasHits[1];

def upBiasAccuracy = if upBiasCount > 0 then upBiasHits / upBiasCount else 0;
def downBiasAccuracy = if downBiasCount > 0 then downBiasHits / downBiasCount else 0;

# Add labels for both biases
AddLabel(
    yes,
    " Up Bias above ORH Success: " + 
        upBiasHits + 
        " / " + 
        upBiasCount + 
        " (" + 
        AsPercent(upBiasAccuracy) + 
        ")" + "  ",
    Color.CYAN
);

AddLabel(
    yes,
    " Down Bias below ORL Success: " + 
        downBiasHits + 
        " / " + 
        downBiasCount + 
        " (" + 
        AsPercent(downBiasAccuracy) + 
        ")" + "  ",
    Color.MAGENTA
);

# Add after the up and down bias labels:

def totalBiasHits = upBiasHits + downBiasHits;
def totalBiasCount = upBiasCount + downBiasCount;
def totalBiasAccuracy = if totalBiasCount > 0 then totalBiasHits / totalBiasCount else 0;

AddLabel(
    yes,
    " Total Bias above/below ORH/ORL Success: " + 
        totalBiasHits + 
        " / " + 
        totalBiasCount + 
        " (" + 
        AsPercent(totalBiasAccuracy) + 
        ")" + "  ",
    Color.WHITE
);

So I also tried to get labels based on if an up or down bias day crossed the ATR levels for above ORH or ORL respectively which I really didn't think would be that hard but for some reason I can't for the life of me get it to work correctly. Most of the time I was getting N/A values for the ATR labels but I have a version here that has labels for hitting the ATR labels but I don't think the numbers are actually correct but if someone more code savvy than me likes this idea and wants to fix it go for it!

1736740163752.png


Share link: https://tos.mx/!yJK8U3Hh

Code:

Code:
# Combined Opening Range Breakout with Volume Profile
# Original ORB by KumoBob, Modified by Clayburgs
# Volume Profile integration added 2025
# Merged with "6th-candle dot" + corrected accuracy label logic

declare upper;

def na = Double.NaN;

############### Volume Profile Section ##############
def TS = TickSize();
def t = getTime() crosses RegularTradingStart(getYYYYMMDD())
        or
        getTime() crosses above RegularTradingStart(getYYYYMMDD()) +
                                aggregationPeriod.Thirty_Min;

profile vol = VolumeProfile(getSymbol(), TS, t, 0, 4, 68);

input showClouds = yes;  # Add this line after other inputs

def pc = if IsNaN(vol.GetPointOfControl())
         then pc[1]
         else vol.GetPointOfControl();
def hVA = if IsNaN(vol.GetHighestValueArea())
          then hVA[1]
          else vol.GetHighestValueArea();
def lVA = if IsNaN(vol.GetLowestValueArea())
          then lVA[1]
          else vol.GetLowestValueArea();

# Volume Profile Plots
plot POC = Round(pc / TS, 0) * TS;
POC.SetDefaultColor(Color.Magenta);
POC.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
POC.SetLineWeight(2);

plot VAHigh = Round(hVA / TS, 0) * TS;
VAHigh.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
VAHigh.SetDefaultColor(Color.white);
VAHigh.SetLineWeight(1);

plot VALow = Round(lVA / TS, 0) * TS;
VALow.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
VALow.SetDefaultColor(Color.white);
VALow.SetLineWeight(1);

# Show volume profile histogram
vol.Show(Color.CYAN, Color.GRAY, Color.CYAN, 15);

############### Directional Day Filter Line (first 5min OR) ##############
input ORBegin = 0930;
input OREnd   = 0935;
input ShowTodayOnly = { default "No", "Yes"};
def s = ShowTodayOnly;

# Create logic for OR definition: 1 if between first 5 minutes
def ORActive = if secondsTillTime(OREnd) > 0 and secondsFromTime(ORBegin) >= 0
               then 1
               else 0;

def today = if s == 0
               or (getDay() == getLastDay() and secondsFromTime(ORBegin) >= 0)
            then 1
            else 0;

# Track OR High:
rec ORHigh = if ORHigh[1] == 0 or (ORActive[1] == 0 and ORActive == 1)
             then high
             else if ORActive and high > ORHigh[1]
                  then high
                  else ORHigh[1];
# Track OR Low:
rec ORLow = if ORLow[1] == 0 or (ORActive[1] == 0 and ORActive == 1)
            then low
            else if ORActive and low < ORLow[1]
                 then low
                 else ORLow[1];

def ORWidth = ORHigh - ORLow;

# Middle of the first 5min OR:
def firstORMean = (ORHigh + ORLow) / 2;

def ORHA = if ORActive or today < 1 then na else ORHigh;
def ORLA = if ORActive or today < 1 then na else ORLow;
def O    = ORHA - (ORHA - ORLA) / 2;

plot ORL = if (O == 0) then na else O;
ORL.SetDefaultColor(Color.YELLOW);
ORL.SetStyle(Curve.LONG_DASH);
ORL.SetLineWeight(3);

################## 30-min OR lines #####################
input ORBegin2 = 0930;
input OREnd2   = 1000;

def ORActive2 = if secondsTillTime(OREnd2) > 0 and secondsFromTime(ORBegin2) >= 0
                then 1
                else 0;

rec ORHigh2 = if ORHigh2[1] == 0 or (ORActive2[1] == 0 and ORActive2 == 1)
              then high
              else if ORActive2 and high > ORHigh2[1]
                   then high
                   else ORHigh2[1];
rec ORLow2 = if ORLow2[1] == 0 or (ORActive2[1] == 0 and ORActive2 == 1)
             then low
             else if ORActive2 and low < ORLow2[1]
                  then low
                  else ORLow2[1];

plot ORH2 = if ORActive2 or today < 1 then na else ORHigh2;
plot ORL2 = if ORActive2 or today < 1 then na else ORLow2;

ORH2.SetDefaultColor(Color.LIGHT_GREEN);
ORH2.SetStyle(Curve.LONG_DASH);
ORH2.SetLineWeight(3);

ORL2.SetDefaultColor(Color.LIGHT_RED);
ORL2.SetStyle(Curve.LONG_DASH);
ORL2.SetLineWeight(3);

# Optionally, add a cloud
AddCloud(
    if showClouds then ORL  else na,
    if showClouds then ORH2 else na,
    Color.GREEN,
    Color.LIGHT_GREEN
);

AddCloud(
    if showClouds then ORL2 else na,
    if showClouds then ORL  else na,
    Color.RED,
    Color.LIGHT_RED
);

##################  (Remove or hide the "d1..d10" & "bd1..bd10" plots) ####################
# We simply comment them out or hide them to avoid the 7 dots and arrow spam.
# -- Original code omitted here for brevity --

##################  Volume Profile "Bias" label ##################
def Span   = (O - ORL2) / (ORH2 - ORL2);
def vpBias = if close > POC then 1 else if close < POC then -1 else 0;
rec colorState =
    if Span > 0.66 or (Span > 0.5 and vpBias > 0) then -1
    else if Span < 0.33 or (Span < 0.5 and vpBias < 0) then 1
    else 0;

AddLabel(
    yes,
    if colorState < 0 then
        " Bias: DOWNWARD (VP: " +
            if vpBias < 0 then "Confirmed" else "Mixed" + ")"
    else if colorState > 0 then
        " Bias: UPWARD (VP: " +
            if vpBias > 0 then "Confirmed" else "Mixed" + ")"
    else
        " Bias: NEUTRAL ",
    if colorState < 0 then Color.RED
    else if colorState > 0 then Color.GREEN
    else Color.YELLOW
);

##################  Inside/Above/Below OR label ##################
def crossingORH = close crosses ORH2;
def crossingORL = close crosses ORL2;
def nearORH = AbsValue(close - ORH2) <= (ORH2 * 0.0005);
def nearORL = AbsValue(close - ORL2) <= (ORH2 * 0.0005);

AddLabel(
    yes,
    if nearORH then
        " CROSSING ORH! VP: " + if close > POC then "Above POC" else "Below POC"
    else if nearORL then
        " CROSSING ORL! VP: " + if close > POC then "Above POC" else "Below POC"
    else if close > ORH2 then
        "Above ORH"
    else if close < ORL2 then
        " Below ORL "
    else
        " Inside OR ",
    if nearORH then
        Color.CYAN
    else if nearORL then
        Color.PINK
    else if close > ORH2 then
        Color.GREEN
    else if close < ORL2 then
        Color.RED
    else
        Color.WHITE
);

##################  STATS LOGIC (time-based)  ##################
#   This part yields the final "Accuracy: X / Y" label
#   based on the candle at 9:55 and the candle at 15:55
# -------------------------------------------------------------
################################################################################
# BAR-COUNT BASED LOGIC
################################################################################

def newDay = GetDay() <> GetDay()[1];

# Only count bars in RTH (9:30 - 16:00 ET):
def isRTHbar = SecondsFromTime(0930) >= 0 and SecondsTillTime(1600) > 0;

# Count bars from the open each day:
rec dayBarCounter =
    if newDay and isRTHbar then 1
    else if isRTHbar and !newDay then dayBarCounter[1] + 1
    else dayBarCounter[1];

# The 6th 5-minute bar is effectively 9:55; the 78th bar is 15:55:
def barEndsAtThirtyMin = (dayBarCounter == 6);
def barEndsDay         = (dayBarCounter == 78);

################################################################################
# DETERMINE DIRECTIONS AT 9:55 & 15:55
################################################################################

rec directionAt30 =
    if newDay then
        Double.NaN
    else if barEndsAtThirtyMin then
        if close > firstORMean then 1 else -1
    else
        directionAt30[1];

rec directionAtClose =
    if newDay then
        Double.NaN
    else if barEndsDay then
        if close > firstORMean then 1 else -1
    else
        directionAtClose[1];

################################################################################
# ACCURACY STATS
################################################################################

# We only increment totalCount and hitCount at the final bar of each day (#78).
rec totalCount =
    if IsNaN(totalCount[1]) then 0
    else if barEndsDay then
        totalCount[1] + 1
    else
        totalCount[1];

rec hitCount =
    if IsNaN(hitCount[1]) then 0
    else if barEndsDay then
        hitCount[1] +
        (if directionAt30 == directionAtClose then 1 else 0)
    else
        hitCount[1];

def accuracy = if totalCount > 0 then hitCount / totalCount else 0;

AddLabel(
    yes,
    " Accuracy: "
        + hitCount
        + " / "
        + totalCount
        + "  ("
        + AsPercent(accuracy)
        + ")" + "  ",
    if accuracy >= 0.5 then Color.GREEN else Color.RED
);

################################################################################
# 4)  Boolean Wedges at 6th bar & final bar
################################################################################

# -- 6th bar wedge(s) --
plot wedgeUp30 =
    if barEndsAtThirtyMin and directionAt30 == 1
    then high
    else Double.NaN;
wedgeUp30.SetPaintingStrategy(PaintingStrategy.BOOLEAN_WEDGE_UP);
wedgeUp30.SetDefaultColor(Color.CYAN);
wedgeUp30.SetLineWeight(3);

plot wedgeDown30 =
    if barEndsAtThirtyMin and directionAt30 == -1
    then low
    else Double.NaN;
wedgeDown30.SetPaintingStrategy(PaintingStrategy.BOOLEAN_WEDGE_DOWN);
wedgeDown30.SetDefaultColor(Color.MAGENTA);
wedgeDown30.SetLineWeight(3);


# -- Final bar wedge(s) --
plot wedgeUpFinal =
    if barEndsDay and directionAtClose == 1
    then high
    else Double.NaN;
wedgeUpFinal.SetPaintingStrategy(PaintingStrategy.BOOLEAN_WEDGE_UP);
wedgeUpFinal.SetDefaultColor(Color.CYAN);
wedgeUpFinal.SetLineWeight(3);

plot wedgeDownFinal =
    if barEndsDay and directionAtClose == -1
    then low
    else Double.NaN;
wedgeDownFinal.SetPaintingStrategy(PaintingStrategy.BOOLEAN_WEDGE_DOWN);
wedgeDownFinal.SetDefaultColor(Color.MAGENTA);
wedgeDownFinal.SetLineWeight(3);

# Add these variables after the existing stats logic section:
# Track inside OR closes at end of day
rec insideORCloseCount =
    if IsNaN(insideORCloseCount[1]) then 0
    else if barEndsDay then
        if close > ORL2 and close < ORH2 then
            insideORCloseCount[1] + 1
        else
            insideORCloseCount[1]
    else
        insideORCloseCount[1];

def insideORPercentage = if totalCount > 0 then insideORCloseCount / totalCount else 0;

AddLabel(
    yes,
    " Inside OR Closes: " +
        insideORCloseCount +
        " / " +
        totalCount +
        "  (" +
        AsPercent(insideORPercentage) +
        ")" + "  ",
    Color.WHITE
);

# Add these variables after the existing stats logic section:

# Track up bias (cyan wedge) success
rec upBiasCount =
    if IsNaN(upBiasCount[1]) then 0
    else if barEndsDay then
        if directionAt30[1] == 1 then
            upBiasCount[1] + 1
        else
            upBiasCount[1]
    else
        upBiasCount[1];

rec upBiasHits =
    if IsNaN(upBiasHits[1]) then 0
    else if barEndsDay then
        if directionAt30[1] == 1 and close > ORH2 then
            upBiasHits[1] + 1
        else
            upBiasHits[1]
    else
        upBiasHits[1];

# Track down bias (pink wedge) success
rec downBiasCount =
    if IsNaN(downBiasCount[1]) then 0
    else if barEndsDay then
        if directionAt30[1] == -1 then
            downBiasCount[1] + 1
        else
            downBiasCount[1]
    else
        downBiasCount[1];

rec downBiasHits =
    if IsNaN(downBiasHits[1]) then 0
    else if barEndsDay then
        if directionAt30[1] == -1 and close < ORL2 then
            downBiasHits[1] + 1
        else
            downBiasHits[1]
    else
        downBiasHits[1];

def upBiasAccuracy = if upBiasCount > 0 then upBiasHits / upBiasCount else 0;
def downBiasAccuracy = if downBiasCount > 0 then downBiasHits / downBiasCount else 0;

# Add labels for both biases
AddLabel(
    yes,
    " Up Bias above ORH Success: " +
        upBiasHits +
        " / " +
        upBiasCount +
        " (" +
        AsPercent(upBiasAccuracy) +
        ")" + "  ",
    Color.CYAN
);

AddLabel(
    yes,
    " Down Bias below ORL Success: " +
        downBiasHits +
        " / " +
        downBiasCount +
        " (" +
        AsPercent(downBiasAccuracy) +
        ")" + "  ",
    Color.MAGENTA
);

# Add after the up and down bias labels:

def totalBiasHits = upBiasHits + downBiasHits;
def totalBiasCount = upBiasCount + downBiasCount;
def totalBiasAccuracy = if totalBiasCount > 0 then totalBiasHits / totalBiasCount else 0;

AddLabel(
    yes,
    " Total Bias above/below ORH/ORL Success: " +
        totalBiasHits +
        " / " +
        totalBiasCount +
        " (" +
        AsPercent(totalBiasAccuracy) +
        ")" + "  ",
    Color.WHITE
);

# Add this after the existing inputs section and before the Volume Profile section:
input atrLength = 14;  # Length for ATR calculation
input showATRLines = yes;  # Toggle for ATR lines visibility
input atrTolerance = 0.0005;  # Add tolerance for ATR crossing detection

# Calculate ATR
def atr = reference ATR(atrLength);

# Calculate ATR extension levels above ORH2
plot ATR1_High = if !ORActive2 and today >= 1 and showATRLines
                 then ORH2 + atr
                 else na;
plot ATR2_High = if !ORActive2 and today >= 1 and showATRLines
                 then ORH2 + (2 * atr)
                 else na;

# Calculate ATR extension levels below ORL2
plot ATR1_Low = if !ORActive2 and today >= 1 and showATRLines
                then ORL2 - atr
                else na;
plot ATR2_Low = if !ORActive2 and today >= 1 and showATRLines
                then ORL2 - (2 * atr)
                else na;

# Style ATR lines (unchanged)
ATR1_High.SetDefaultColor(Color.LIGHT_GREEN);
ATR1_High.SetStyle(Curve.SHORT_DASH);
ATR1_High.SetLineWeight(2);

ATR2_High.SetDefaultColor(Color.LIGHT_GREEN);
ATR2_High.SetStyle(Curve.SHORT_DASH);
ATR2_High.SetLineWeight(1);

ATR1_Low.SetDefaultColor(Color.LIGHT_RED);
ATR1_Low.SetStyle(Curve.SHORT_DASH);
ATR1_Low.SetLineWeight(2);

ATR2_Low.SetDefaultColor(Color.LIGHT_RED);
ATR2_Low.SetStyle(Curve.SHORT_DASH);
ATR2_Low.SetLineWeight(1);

# Track Up Bias (Cyan) ATR hits with tolerance check built into conditions
rec upBiasATR1Count =
    if IsNaN(upBiasATR1Count[1]) then 0
    else if barEndsDay then
        if directionAt30[1] == 1 then
            upBiasATR1Count[1] + 1
        else
            upBiasATR1Count[1]
    else
        upBiasATR1Count[1];

rec upBiasATR1Hits =
    if IsNaN(upBiasATR1Hits[1]) then 0
    else if barEndsDay then
        if directionAt30[1] == 1 and
           (High >= ATR1_High or AbsValue(High - ATR1_High) <= (ATR1_High * atrTolerance)) then
            upBiasATR1Hits[1] + 1
        else
            upBiasATR1Hits[1]
    else
        upBiasATR1Hits[1];

rec upBiasATR2Count =
    if IsNaN(upBiasATR2Count[1]) then 0
    else if barEndsDay then
        if directionAt30[1] == 1 then
            upBiasATR2Count[1] + 1
        else
            upBiasATR2Count[1]
    else
        upBiasATR2Count[1];

rec upBiasATR2Hits =
    if IsNaN(upBiasATR2Hits[1]) then 0
    else if barEndsDay then
        if directionAt30[1] == 1 and
           (High >= ATR2_High or AbsValue(High - ATR2_High) <= (ATR2_High * atrTolerance)) then
            upBiasATR2Hits[1] + 1
        else
            upBiasATR2Hits[1]
    else
        upBiasATR2Hits[1];

# Track Down Bias (Magenta) ATR hits with tolerance check built into conditions
rec downBiasATR1Count =
    if IsNaN(downBiasATR1Count[1]) then 0
    else if barEndsDay then
        if directionAt30[1] == -1 then
            downBiasATR1Count[1] + 1
        else
            downBiasATR1Count[1]
    else
        downBiasATR1Count[1];

rec downBiasATR1Hits =
    if IsNaN(downBiasATR1Hits[1]) then 0
    else if barEndsDay then
        if directionAt30[1] == -1 and
           (Low <= ATR1_Low or AbsValue(Low - ATR1_Low) <= (ATR1_Low * atrTolerance)) then
            downBiasATR1Hits[1] + 1
        else
            downBiasATR1Hits[1]
    else
        downBiasATR1Hits[1];

rec downBiasATR2Count =
    if IsNaN(downBiasATR2Count[1]) then 0
    else if barEndsDay then
        if directionAt30[1] == -1 then
            downBiasATR2Count[1] + 1
        else
            downBiasATR2Count[1]
    else
        downBiasATR2Count[1];

rec downBiasATR2Hits =
    if IsNaN(downBiasATR2Hits[1]) then 0
    else if barEndsDay then
        if directionAt30[1] == -1 and
           (Low <= ATR2_Low or AbsValue(Low - ATR2_Low) <= (ATR2_Low * atrTolerance)) then
            downBiasATR2Hits[1] + 1
        else
            downBiasATR2Hits[1]
    else
        downBiasATR2Hits[1];

# Calculate success rates
def upATR1Success = if upBiasATR1Count > 0 then upBiasATR1Hits / upBiasATR1Count else 0;
def upATR2Success = if upBiasATR2Count > 0 then upBiasATR2Hits / upBiasATR2Count else 0;
def downATR1Success = if downBiasATR1Count > 0 then downBiasATR1Hits / downBiasATR1Count else 0;
def downATR2Success = if downBiasATR2Count > 0 then downBiasATR2Hits / downBiasATR2Count else 0;



# Add labels for ATR statistics
AddLabel(
    yes,
    " Up Bias 1ATR Hits: " +
        upBiasATR1Hits +
        " / " +
        upBiasATR1Count +
        " (" +
        AsPercent(upATR1Success) +
        ")" + "  ",
    Color.CYAN
);

AddLabel(
    yes,
    " Up Bias 2ATR Hits: " +
        upBiasATR2Hits +
        " / " +
        upBiasATR2Count +
        " (" +
        AsPercent(upATR2Success) +
        ")" + "  ",
    Color.CYAN
);

AddLabel(
    yes,
    " Down Bias 1ATR Hits: " +
        downBiasATR1Hits +
        " / " +
        downBiasATR1Count +
        " (" +
        AsPercent(downATR1Success) +
        ")" + "  ",
    Color.MAGENTA
);

AddLabel(
    yes,
    " Down Bias 2ATR Hits: " +
        downBiasATR2Hits +
        " / " +
        downBiasATR2Count +
        " (" +
        AsPercent(downATR2Success) +
        ")" + "  ",
    Color.MAGENTA
);


This is another take on trying to capturing ATR crosses as additional labels, these labels I took from someone else and added some functionality. I believe it accurately captures ATR crosses but it just looks for general ATR crosses it doesn't take into account the day bias which for whatever reason is causing some big issues getting that to work. I don't remember the link to the post and the code doesn't have a header with a name so apologies for not giving credit on that! I will update this area if I find the author post.

1736740331347.png


Share link: https://tos.mx/!I3iQ47Cy

Code:

Code:
# Combined Opening Range Breakout with Volume Profile

# Original ORB by KumoBob, Modified by Clayburgs

# Volume Profile integration added 2025

# Merged with "6th-candle dot" + corrected accuracy label logic



declare upper;



def na = Double.NaN;



############### Volume Profile Section ##############

def TS = TickSize();

def t = getTime() crosses RegularTradingStart(getYYYYMMDD())

        or

        getTime() crosses above RegularTradingStart(getYYYYMMDD()) +

                                aggregationPeriod.Thirty_Min;



profile vol = VolumeProfile(getSymbol(), TS, t, 0, 4, 68);



input showClouds = yes;  # Add this line after other inputs



def pc = if IsNaN(vol.GetPointOfControl())

         then pc[1]

         else vol.GetPointOfControl();

def hVA = if IsNaN(vol.GetHighestValueArea())

          then hVA[1]

          else vol.GetHighestValueArea();

def lVA = if IsNaN(vol.GetLowestValueArea())

          then lVA[1]

          else vol.GetLowestValueArea();



# Volume Profile Plots

plot POC = Round(pc / TS, 0) * TS;

POC.SetDefaultColor(Color.Magenta);

POC.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);

POC.SetLineWeight(2);



plot VAHigh = Round(hVA / TS, 0) * TS;

VAHigh.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);

VAHigh.SetDefaultColor(Color.white);

VAHigh.SetLineWeight(1);



plot VALow = Round(lVA / TS, 0) * TS;

VALow.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);

VALow.SetDefaultColor(Color.white);

VALow.SetLineWeight(1);



# Show volume profile histogram

vol.Show(Color.CYAN, Color.GRAY, Color.CYAN, 15);



############### Directional Day Filter Line (first 5min OR) ##############

input ORBegin = 0930;

input OREnd   = 0935;

input ShowTodayOnly = { default "No", "Yes"};

def s = ShowTodayOnly;



# Create logic for OR definition: 1 if between first 5 minutes

def ORActive = if secondsTillTime(OREnd) > 0 and secondsFromTime(ORBegin) >= 0

               then 1

               else 0;



def today = if s == 0

               or (getDay() == getLastDay() and secondsFromTime(ORBegin) >= 0)

            then 1

            else 0;



# Track OR High:

rec ORHigh = if ORHigh[1] == 0 or (ORActive[1] == 0 and ORActive == 1)

             then high

             else if ORActive and high > ORHigh[1]

                  then high

                  else ORHigh[1];

# Track OR Low:

rec ORLow = if ORLow[1] == 0 or (ORActive[1] == 0 and ORActive == 1)

            then low

            else if ORActive and low < ORLow[1]

                 then low

                 else ORLow[1];



def ORWidth = ORHigh - ORLow;



# Middle of the first 5min OR:

def firstORMean = (ORHigh + ORLow) / 2;



def ORHA = if ORActive or today < 1 then na else ORHigh;

def ORLA = if ORActive or today < 1 then na else ORLow;

def O    = ORHA - (ORHA - ORLA) / 2;



plot ORL = if (O == 0) then na else O;

ORL.SetDefaultColor(Color.YELLOW);

ORL.SetStyle(Curve.LONG_DASH);

ORL.SetLineWeight(3);



################## 30-min OR lines #####################

input ORBegin2 = 0930;

input OREnd2   = 1000;



def ORActive2 = if secondsTillTime(OREnd2) > 0 and secondsFromTime(ORBegin2) >= 0

                then 1

                else 0;



rec ORHigh2 = if ORHigh2[1] == 0 or (ORActive2[1] == 0 and ORActive2 == 1)

              then high

              else if ORActive2 and high > ORHigh2[1]

                   then high

                   else ORHigh2[1];

rec ORLow2 = if ORLow2[1] == 0 or (ORActive2[1] == 0 and ORActive2 == 1)

             then low

             else if ORActive2 and low < ORLow2[1]

                  then low

                  else ORLow2[1];



plot ORH2 = if ORActive2 or today < 1 then na else ORHigh2;

plot ORL2 = if ORActive2 or today < 1 then na else ORLow2;



ORH2.SetDefaultColor(Color.LIGHT_GREEN);

ORH2.SetStyle(Curve.LONG_DASH);

ORH2.SetLineWeight(3);



ORL2.SetDefaultColor(Color.LIGHT_RED);

ORL2.SetStyle(Curve.LONG_DASH);

ORL2.SetLineWeight(3);



# Optionally, add a cloud

AddCloud(

    if showClouds then ORL  else na,

    if showClouds then ORH2 else na,

    Color.GREEN,

    Color.LIGHT_GREEN

);



AddCloud(

    if showClouds then ORL2 else na,

    if showClouds then ORL  else na,

    Color.RED,

    Color.LIGHT_RED

);



##################  (Remove or hide the "d1..d10" & "bd1..bd10" plots) ####################

# We simply comment them out or hide them to avoid the 7 dots and arrow spam.

# -- Original code omitted here for brevity --



##################  Volume Profile "Bias" label ##################

def Span   = (O - ORL2) / (ORH2 - ORL2);

def vpBias = if close > POC then 1 else if close < POC then -1 else 0;

rec colorState =

    if Span > 0.66 or (Span > 0.5 and vpBias > 0) then -1

    else if Span < 0.33 or (Span < 0.5 and vpBias < 0) then 1

    else 0;



AddLabel(

    yes,

    if colorState < 0 then

        " Bias: DOWNWARD (VP: " +

            if vpBias < 0 then "Confirmed" else "Mixed" + ")"

    else if colorState > 0 then

        " Bias: UPWARD (VP: " +

            if vpBias > 0 then "Confirmed" else "Mixed" + ")"

    else

        " Bias: NEUTRAL ",

    if colorState < 0 then Color.RED

    else if colorState > 0 then Color.GREEN

    else Color.YELLOW

);



##################  Inside/Above/Below OR label ##################

def crossingORH = close crosses ORH2;

def crossingORL = close crosses ORL2;

def nearORH = AbsValue(close - ORH2) <= (ORH2 * 0.0005);

def nearORL = AbsValue(close - ORL2) <= (ORH2 * 0.0005);



AddLabel(

    yes,

    if nearORH then

        " CROSSING ORH! VP: " + if close > POC then "Above POC" else "Below POC"

    else if nearORL then

        " CROSSING ORL! VP: " + if close > POC then "Above POC" else "Below POC"

    else if close > ORH2 then

        "Above ORH"

    else if close < ORL2 then

        " Below ORL "

    else

        " Inside OR ",

    if nearORH then

        Color.CYAN

    else if nearORL then

        Color.PINK

    else if close > ORH2 then

        Color.GREEN

    else if close < ORL2 then

        Color.RED

    else

        Color.WHITE

);



##################  STATS LOGIC (time-based)  ##################

#   This part yields the final "Accuracy: X / Y" label

#   based on the candle at 9:55 and the candle at 15:55

# -------------------------------------------------------------

################################################################################

# BAR-COUNT BASED LOGIC

################################################################################



def newDay = GetDay() <> GetDay()[1];



# Only count bars in RTH (9:30 - 16:00 ET):

def isRTHbar = SecondsFromTime(0930) >= 0 and SecondsTillTime(1600) > 0;



# Count bars from the open each day:

rec dayBarCounter =

    if newDay and isRTHbar then 1

    else if isRTHbar and !newDay then dayBarCounter[1] + 1

    else dayBarCounter[1];



# The 6th 5-minute bar is effectively 9:55; the 78th bar is 15:55:

def barEndsAtThirtyMin = (dayBarCounter == 6);

def barEndsDay         = (dayBarCounter == 78);



################################################################################

# DETERMINE DIRECTIONS AT 9:55 & 15:55

################################################################################



rec directionAt30 =

    if newDay then

        Double.NaN

    else if barEndsAtThirtyMin then

        if close > firstORMean then 1 else -1

    else

        directionAt30[1];



rec directionAtClose =

    if newDay then

        Double.NaN

    else if barEndsDay then

        if close > firstORMean then 1 else -1

    else

        directionAtClose[1];



################################################################################

# ACCURACY STATS

################################################################################



# We only increment totalCount and hitCount at the final bar of each day (#78).

rec totalCount =

    if IsNaN(totalCount[1]) then 0

    else if barEndsDay then

        totalCount[1] + 1

    else

        totalCount[1];



rec hitCount =

    if IsNaN(hitCount[1]) then 0

    else if barEndsDay then

        hitCount[1] +

        (if directionAt30 == directionAtClose then 1 else 0)

    else

        hitCount[1];



def accuracy = if totalCount > 0 then hitCount / totalCount else 0;



AddLabel(

    yes,

    " Accuracy: "

        + hitCount

        + " / "

        + totalCount

        + "  ("

        + AsPercent(accuracy)

        + ")" + "  ",

    if accuracy >= 0.5 then Color.GREEN else Color.RED

);



################################################################################

# 4)  Boolean Wedges at 6th bar & final bar

################################################################################



# -- 6th bar wedge(s) --

plot wedgeUp30 =

    if barEndsAtThirtyMin and directionAt30 == 1

    then high

    else Double.NaN;

wedgeUp30.SetPaintingStrategy(PaintingStrategy.BOOLEAN_WEDGE_UP);

wedgeUp30.SetDefaultColor(Color.CYAN);

wedgeUp30.SetLineWeight(3);



plot wedgeDown30 =

    if barEndsAtThirtyMin and directionAt30 == -1

    then low

    else Double.NaN;

wedgeDown30.SetPaintingStrategy(PaintingStrategy.BOOLEAN_WEDGE_DOWN);

wedgeDown30.SetDefaultColor(Color.MAGENTA);

wedgeDown30.SetLineWeight(3);





# -- Final bar wedge(s) --

plot wedgeUpFinal =

    if barEndsDay and directionAtClose == 1

    then high

    else Double.NaN;

wedgeUpFinal.SetPaintingStrategy(PaintingStrategy.BOOLEAN_WEDGE_UP);

wedgeUpFinal.SetDefaultColor(Color.CYAN);

wedgeUpFinal.SetLineWeight(3);



plot wedgeDownFinal =

    if barEndsDay and directionAtClose == -1

    then low

    else Double.NaN;

wedgeDownFinal.SetPaintingStrategy(PaintingStrategy.BOOLEAN_WEDGE_DOWN);

wedgeDownFinal.SetDefaultColor(Color.MAGENTA);

wedgeDownFinal.SetLineWeight(3);



# Add these variables after the existing stats logic section:

# Track inside OR closes at end of day

rec insideORCloseCount =

    if IsNaN(insideORCloseCount[1]) then 0

    else if barEndsDay then

        if close > ORL2 and close < ORH2 then

            insideORCloseCount[1] + 1

        else

            insideORCloseCount[1]

    else

        insideORCloseCount[1];



def insideORPercentage = if totalCount > 0 then insideORCloseCount / totalCount else 0;



AddLabel(

    yes,

    " Inside OR Closes: " +

        insideORCloseCount +

        " / " +

        totalCount +

        "  (" +

        AsPercent(insideORPercentage) +

        ")" + "  ",

    Color.WHITE

);



# Add these variables after the existing stats logic section:



# Track up bias (cyan wedge) success

rec upBiasCount =

    if IsNaN(upBiasCount[1]) then 0

    else if barEndsDay then

        if directionAt30[1] == 1 then

            upBiasCount[1] + 1

        else

            upBiasCount[1]

    else

        upBiasCount[1];



rec upBiasHits =

    if IsNaN(upBiasHits[1]) then 0

    else if barEndsDay then

        if directionAt30[1] == 1 and close > ORH2 then

            upBiasHits[1] + 1

        else

            upBiasHits[1]

    else

        upBiasHits[1];



# Track down bias (pink wedge) success

rec downBiasCount =

    if IsNaN(downBiasCount[1]) then 0

    else if barEndsDay then

        if directionAt30[1] == -1 then

            downBiasCount[1] + 1

        else

            downBiasCount[1]

    else

        downBiasCount[1];



rec downBiasHits =

    if IsNaN(downBiasHits[1]) then 0

    else if barEndsDay then

        if directionAt30[1] == -1 and close < ORL2 then

            downBiasHits[1] + 1

        else

            downBiasHits[1]

    else

        downBiasHits[1];



def upBiasAccuracy = if upBiasCount > 0 then upBiasHits / upBiasCount else 0;

def downBiasAccuracy = if downBiasCount > 0 then downBiasHits / downBiasCount else 0;



# Add labels for both biases

AddLabel(

    yes,

    " Up Bias above ORH Success: " +

        upBiasHits +

        " / " +

        upBiasCount +

        " (" +

        AsPercent(upBiasAccuracy) +

        ")" + "  ",

    Color.CYAN

);



AddLabel(

    yes,

    " Down Bias below ORL Success: " +

        downBiasHits +

        " / " +

        downBiasCount +

        " (" +

        AsPercent(downBiasAccuracy) +

        ")" + "  ",

    Color.MAGENTA

);



# Add after the up and down bias labels:



def totalBiasHits = upBiasHits + downBiasHits;

def totalBiasCount = upBiasCount + downBiasCount;

def totalBiasAccuracy = if totalBiasCount > 0 then totalBiasHits / totalBiasCount else 0;



AddLabel(

    yes,

    " Total Bias above/below ORH/ORL Success: " +

        totalBiasHits +

        " / " +

        totalBiasCount +

        " (" +

        AsPercent(totalBiasAccuracy) +

        ")" + "  ",

    Color.WHITE

);



input startHour = 0930;

input endHour = 1000;

input atrLength = 14;

input atrMult = 2;



def firstHour = if SecondsFromTime(startHour) >= 0 and SecondsTillTime(endHour) >= 0 then 1 else 0;

def remainderOfDay = if SecondsFromTime(endHour) >= 0 then 1 else 0;



# Track both high and low of first hour

rec highInFirstHour = if firstHour and (high > highInFirstHour[1] or !firstHour[1]) then high else highInFirstHour[1];

rec lowInFirstHour = if firstHour and (low < lowInFirstHour[1] or !firstHour[1]) then low else lowInFirstHour[1];



def ATR = reference ATR(atrLength);



# Calculate ATR levels

def ORH_1ATR = highInFirstHour + ATR;

def ORH_2ATR = highInFirstHour + 2 * ATR;

def ORL_1ATR = lowInFirstHour - ATR;

def ORL_2ATR = lowInFirstHour - 2 * ATR;



# Plot main OR lines

plot highLine = if remainderOfDay then highInFirstHour else Double.NaN;

plot lowLine = if remainderOfDay then lowInFirstHour else Double.NaN;

highLine.SetDefaultColor(Color.GREEN);

lowLine.SetDefaultColor(Color.RED);



# Plot ATR levels

plot ORH1ATR = if remainderOfDay then ORH_1ATR else Double.NaN;

plot ORH2ATR = if remainderOfDay then ORH_2ATR else Double.NaN;

plot ORL1ATR = if remainderOfDay then ORL_1ATR else Double.NaN;

plot ORL2ATR = if remainderOfDay then ORL_2ATR else Double.NaN;



# Style ATR level lines

ORH1ATR.SetDefaultColor(Color.WHITE);

ORH2ATR.SetDefaultColor(Color.YELLOW);

ORL1ATR.SetDefaultColor(Color.WHITE);

ORL2ATR.SetDefaultColor(Color.YELLOW);

ORH1ATR.SetStyle(Curve.SHORT_DASH);

ORH2ATR.SetStyle(Curve.SHORT_DASH);

ORL1ATR.SetStyle(Curve.SHORT_DASH);

ORL2ATR.SetStyle(Curve.SHORT_DASH);



# Track crosses above ORH by 1 and 2 ATR

rec triggeredAbove2ATR = if GetDay() != GetDay()[1] then 0

    else if remainderOfDay and close > ORH_2ATR and !triggeredAbove2ATR[1] then 1

    else triggeredAbove2ATR[1];



rec triggeredAbove1ATR = if GetDay() != GetDay()[1] then 0

    else if remainderOfDay and close > ORH_1ATR and !triggeredAbove1ATR[1] then 1

    else triggeredAbove1ATR[1];



# Track crosses below ORL by 1 and 2 ATR

rec triggeredBelow2ATR = if GetDay() != GetDay()[1] then 0

    else if remainderOfDay and close < ORL_2ATR and !triggeredBelow2ATR[1] then 1

    else triggeredBelow2ATR[1];



rec triggeredBelow1ATR = if GetDay() != GetDay()[1] then 0

    else if remainderOfDay and close < ORL_1ATR and !triggeredBelow1ATR[1] then 1

    else triggeredBelow1ATR[1];



# Reset conditions for each direction

rec crossedBackAbove = if (triggeredBelow1ATR or triggeredBelow2ATR) and close > ORL_1ATR then 1

    else if GetDay() != GetDay()[1] then 0

    else crossedBackAbove[1];



rec crossedBackBelow = if (triggeredAbove1ATR or triggeredAbove2ATR) and close < ORH_1ATR then 1

    else if GetDay() != GetDay()[1] then 0

    else crossedBackBelow[1];



# Counters for all crosses

rec crossesAbove1ATR = if triggeredAbove1ATR and !triggeredAbove1ATR[1] and !crossedBackBelow then crossesAbove1ATR[1] + 1

    else crossesAbove1ATR[1];

rec crossesAbove2ATR = if triggeredAbove2ATR and !triggeredAbove2ATR[1] and !crossedBackBelow then crossesAbove2ATR[1] + 1

    else crossesAbove2ATR[1];

rec crossesBelow1ATR = if triggeredBelow1ATR and !triggeredBelow1ATR[1] and !crossedBackAbove then crossesBelow1ATR[1] + 1

    else crossesBelow1ATR[1];

rec crossesBelow2ATR = if triggeredBelow2ATR and !triggeredBelow2ATR[1] and !crossedBackAbove then crossesBelow2ATR[1] + 1

    else crossesBelow2ATR[1];



# Labels for all crosses

AddLabel(yes, "Crosses Above by 1 ATR: " + crossesAbove1ATR + "  ", Color.WHITE);

AddLabel(yes, "Crosses Above by 2 ATR: " + crossesAbove2ATR + "  ", Color.YELLOW);

AddLabel(yes, "Crosses Below by 1 ATR: " + crossesBelow1ATR + "  ", Color.WHITE);

AddLabel(yes, "Crosses Below by 2 ATR: " + crossesBelow2ATR + "  ", Color.YELLOW);



# Plot arrows for all crosses

plot ArrowUp1ATR = if triggeredAbove1ATR and !triggeredAbove1ATR[1] and !crossedBackBelow then high else Double.NaN;

plot ArrowUp2ATR = if triggeredAbove2ATR and !triggeredAbove2ATR[1] and !crossedBackBelow then high else Double.NaN;

plot ArrowDown1ATR = if triggeredBelow1ATR and !triggeredBelow1ATR[1] and !crossedBackAbove then low else Double.NaN;

plot ArrowDown2ATR = if triggeredBelow2ATR and !triggeredBelow2ATR[1] and !crossedBackAbove then low else Double.NaN;



ArrowUp1ATR.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_UP);

ArrowUp2ATR.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_UP);

ArrowDown1ATR.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_DOWN);

ArrowDown2ATR.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_DOWN);



ArrowUp1ATR.SetLineWeight(2);

ArrowUp2ATR.SetLineWeight(3);

ArrowDown1ATR.SetLineWeight(2);

ArrowDown2ATR.SetLineWeight(3);



ArrowUp1ATR.SetDefaultColor(Color.WHITE);

ArrowUp2ATR.SetDefaultColor(Color.MAGENTA);

ArrowDown1ATR.SetDefaultColor(Color.WHITE);

ArrowDown2ATR.SetDefaultColor(Color.MAGENTA);



# End Code

Overall I am using the first code I posted for now unless I or someone in the comments can make the ATR labels more accurate.

Things I am looking to add in future iterations:

  • I want to make it so you can toggle the volume profile on / off and for some reason I can't get that to work very well.
  • Add some more toggle-able features
  • Come up with an actual strategy around using this indicator
  • You may notice on the 180 day timeframe that it only counts 173 instances. I have no clue why it happens but there are 7 missing instances. 4 of them are from a shorter trading day so it never had a 78th bar (my attempts to account for that didn't work) and then 3 I don't have any clue why they aren't showing up, there is at least one instance I found where there is a full trading day but the 78th candle doesn't have a wedge for some reason. But since it was only 3 instances and those wedges are just used for statistical purposes and don't really have any basis on trading decisions I didn't spend too much time trying to figure out why that was happening. I think capturing 96% of the days is fine for testing the theory out.

If anyone has any ideas on how to make this better I would love to hear them!

My current idea is to use a flexible grid of 10 or so stocks and that is why I have the two dynamic labels so I can see the action live of what is happening!

I will do my best to update this main post with any new versions or updates.

Let me know if you have any questions and enjoy / let me know if you find it useful!!
 
Last edited:

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

An excellent analysis!

It should be pointed out that the premise:
Overnight orders accumulate. Those orders being placed during the first 15 minutes of Regular Trading Hours combined with the typical high volume in the first 30 minutes of trading make this the most volatile trading period of the day.

Requires the equity to have the liquidity and volatility to attract the institutional traders that are driving the overnight trades and the ORB volatility.

Right now, "Magnificent Seven" stocks - which include Apple, Amazon, Alphabet, Meta, Microsoft, Nvidia, and Tesla - currently make up around 30% of the S&P 500 Index's market value.
Therefore, they would be most likely to fit this hypothesis, the most consistently.

The most volatile will also qualify; sometimes even more profitably, but not consistently.
Therefore, with much greater risk:
  • Tesla, Inc. TSLA. Consumer Discretionary.
  • Warner Bros Discovery Inc. WBD. Communication Services.
  • Globe Life Inc. GL. Financials.
  • DexCom Inc. DXCM. Health Care.
  • Broadcom Inc. AVGO. Information Technology.
  • Estee Lauder Cos. A. EL. Consumer Staples.
  • Enphase Energy Inc. ENPH. Information Technology.
  • Vistra Corp. VST. Utilities.

All other stocks would require a catalyst to provide the drive to the overnight accumulation.

This is an impressive contribution.
Thank you for your hard work and insights!
 

Similar threads

Not the exact question you're looking for?

Start a new thread and receive assistance from our community.

87k+ Posts
119 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