Opening Range Indicator with Measured Moves and VWAP For ThinkOrSwim

Hello again,

I'm back with a bit of a different take on the Opening Range. This is a relatively simple indicator that analyzes movement during a specified time period and plots various lines based on that information. I am anchoring a VWAP (with standard deviations) to this start time as well to better judge the prevailing trend. The opening range is usually a daytrading tool and as such this will not display on daily or higher timeframes. There is another similar concept based on the weekly open range but that is a topic for another time.

View attachment 12022

In the image above, I have added the study twice. Once, from the European session open and once from the US Open. You will see the blue-ish lines representing the opening range for each of those periods with a mid-line and some extended targets based on the range. This study is intended to provide context to your trading system but is not a strategy in and of itself. If you are interested in learning more about why Opening Ranges are important and some different strategies to trade them, there is a more complex study with background information here: Opening Range Breakout.

There are options in this study to show the range as a label in the top left, to show/hide the extended targets and also to add additional 1/4 and 3/4 lines inside of the range. You can also enable bubbles to show that display the OR highs and lows but need to have an expansion area of 5 bars or so to display properly. And finally, there is an option to color your candles if they fall outside of the OR.

The options have two associated timeframes. One for the opening range you want to analyze (eg. 9:30 to 9:45) and another for the period for the lines to draw (eg. 9:30 to 16:00). In the image above, the first version has 2:30 to 3:30 as the European open range and 2:30 to 9:00 as the time to draw the lines. The second version (in the same chart) is 9:30 to 9:45 and then 9:30 to 16:00 for the line display. Hopefully this makes sense.

This study will work best on timeframes less than 1 hour and will perform will on tick charts. Range charts and renko charts will have some difficulties with the study and the VWAP will not work on those at all. This one was pretty fun to build. Please let me know if you have ideas for improvement.

Ruby:
# Opening Range w/VWAP
# Created by @tony_futures
# Inspired by @mighigandolf 's tweets

declare hide_on_daily;
input displayType = { "At timed start", default  "From RTH Start"};
input startTime = 0930;
input End_Time = 0945;
input showTodayOnly = no;
input showLabels = yes;
input showVWAP = yes;
input showVWAPDevs = yes;
def RTH;

switch (displayType)
{
    case "At Timed Start":
      RTH = secondsFromTime(startTime) >= 0;
     
    case "From RTH Start":
      RTH = GetTime() >= RegularTradingStart(GetYYYYMMDD());
}
input anchorTime = 0930;
input anchorEnd = 1600;
def postAnchorTime = if SecondsFromTime(anchorTime) >= 0 then 1 else 0;
def endAchorTime = if SecondsTillTime(anchorEnd) >= 0 then 1 else 0;
def endPlot = secondsFromTime(anchorEnd) >= 0;
def Today = GetLastDay() == GetDay();
def ORActive = (Today OR !showTodayOnly) and RTH and SecondsFromTime(End_Time) < 0;

def ORhigh = if RTH and !RTH[1] then high else if RTH and ORActive and high > ORhigh[1] then high else ORhigh[1];
def ORlow = if RTH and !RTH[1] then low else if RTH and ORActive and low < ORlow[1] then low else ORlow[1];
def OROpen = if RTH and !RTH[1] then open else OROpen[1];
def ORClose = if !ORActive and ORActive[1] then close[1] else ORClose[1];
def ORFullRange = AbsValue(ORHigh - ORLow);
def midPoint = ORLow + (ORFullRange/2);

AddLabel(showLabels, "Open: " + OROpen + " | Close: " + ORClose + " | Range: " + ORFullRange + " |", Color.WHITE);

# setup Colors
DefineGlobalColor("quarterColor", CreateColor(169, 169, 169));
DefineGlobalColor("midColor", CreateColor(132, 76, 130));
DefineGlobalColor("rangeColor", CreateColor(28, 96, 109));
DefineGlobalColor("openColor", CreateColor(109, 84, 44));
DefineGlobalColor("downColor", CreateColor(109, 42, 28));
DefineGlobalColor("upColor", CreateColor(76, 133, 78));
DefineGlobalColor("vwapColor", CreateColor(174, 157, 50));
#

def OREnded = (Today OR !showTodayOnly) and RTH and SecondsFromTime(End_Time) >= 0;
plot ORL = if OREnded and !endPlot then ORlow else Double.NaN;
ORL.SetDefaultColor(GlobalColor("rangeColor"));
ORL.HideBubble();
plot ORH = if OREnded and !endPlot then ORhigh else Double.NaN;
ORH.SetDefaultColor(GlobalColor("rangeColor"));
ORH.HideBubble();
input showMidPoint = yes;

plot mid = if OREnded and !endPlot then midPoint else Double.NaN;
mid.setDefaultColor(GlobalColor("midColor"));
mid.HideBubble();
input showQuarters = no;
def oneQuarter = ORLow + (ORFullRange/4);
def threeQuarter = ORHigh - (ORFullRange/4);
plot oneQLine = if showQuarters and OREnded and !endPlot then oneQuarter else Double.NaN;
oneQLine.setDefaultColor(GlobalColor("quarterColor"));
oneQLine.HideBubble();
plot threeQLine = if showQuarters and OREnded and !endPlot then threeQuarter else Double.NaN;
threeQLine.setDefaultColor(GlobalColor("quarterColor"));
threeQLine.HideBubble();

input showMeasuredTargets = yes;
def upperTarget = (ORHigh + (ORFullRange/2));
plot upper = if showMeasuredTargets and OREnded and !endPlot then upperTarget else Double.NaN;
upper.SetDefaultColor(GlobalColor("upColor"));
upper.HideBubble();
def lowerTarget = (ORLow - (ORFullRange/2));
plot lower = if showMeasuredTargets and OREnded and !endPlot then lowerTarget else Double.NaN;
lower.SetDefaultColor(GlobalColor("downColor"));
lower.HideBubble();
input showMeasuredTargets2 = no;
def upperTarget2 = (ORHigh + (ORFullRange));
plot upper2 = if showMeasuredTargets2 and OREnded and !endPlot then upperTarget2 else Double.NaN;
upper2.SetDefaultColor(GlobalColor("upColor"));
upper2.HideBubble();
def lowerTarget2 = (ORLow - (ORFullRange));
plot lower2 = if showMeasuredTargets2 and OREnded and !endPlot then lowerTarget2 else Double.NaN;
lower2.SetDefaultColor(GlobalColor("downColor"));
lower2.HideBubble();

#plot anchored VWAP for the current day
def  volumeSum = CompoundValue(1, if postAnchorTime and endAchorTime then volumeSum[1] + volume else 0, volume);
def  volumeVwapSum = CompoundValue(1, if postAnchorTime and endAchorTime then volumeVwapSum[1] + volume * vwap else 0, volume * vwap);
def volumeVwap2Sum = CompoundValue(1, if postAnchorTime and endAchorTime then volumeVwap2Sum[1] + volume * Sqr(vwap) else 0, volume * Sqr(vwap));
def price = volumeVwapSum / volumeSum;
def deviation = Sqrt(Max(volumeVwap2Sum / volumeSum - Sqr(price), 0));

input stdDev = 1.0;
def numDevDn = -stdDev;
def numDevUp = stdDev;

plot anchorVWAP = if !showVWAP then Double.NAN else if showVWAP and showTodayOnly and !Today then Double.NaN else if RTH and showVWAP then price else Double.NaN;
anchorVWAP.SetStyle(Curve.FIRM);
anchorVWAP.SetDefaultColor(GlobalColor("vwapColor"));
plot anchorVWAPUpper = if !showVWAPDevs then Double.NaN else if showVWAPDevs and showTodayOnly and !Today then Double.NaN else if RTH and showVWAPDevs then (price + (numDevUp * deviation)) else Double.NaN;
anchorVWAPUpper.SetStyle(Curve.SHORT_DASH);
anchorVWAPUpper.SetDefaultColor(Color.GRAY);
anchorVWAPUpper.HideBubble();
plot anchorVWAPLower = if !showVWAPDevs then Double.NaN else if showVWAPDevs and showTodayOnly and !Today then Double.NaN else if RTH and showVWAPDevs then (price + (numDevDn * deviation)) else Double.NaN;
anchorVWAPLower.SetStyle(Curve.SHORT_DASH);
anchorVWAPLower.SetDefaultColor(Color.GRAY);
anchorVWAPLower.HideBubble();

input colorCandles = no;
AssignPriceColor(if !colorCandles then Color.CURRENT
else if colorCandles and OREnded and high < ORL and high < anchorVWAP then
    GlobalColor("downColor")
else if colorCandles and OREnded and low > ORH and low > anchorVWAP then
    GlobalColor("upColor")     
else Color.CURRENT );

input showOpen = yes;
AddVerticalLine(showOpen and Today and RTH and !RTH[1], concat("Open", ""), GlobalColor("openColor"), curve.POINTS);

input showBubbles = no;
def showBubbleNow = !IsNaN(close) and IsNaN(close[-1]);
AddChartBubble(showBubbles and showBubbleNow[1], ORHigh[1], "OR High", Color.GRAY, yes);
AddChartBubble(showBubbles and showBubbleNow[1], ORLow[1], "OR Low", Color.GRAY, no);
I like this OR indicator the most of the ones shared on the forum, thank you for sharing it. I tried to modify it to allow plotting in the expansion area but haven't gotten that to work. Can you advise if there is a way to easily make it plot only in the expansion area?
 
I like this OR indicator the most of the ones shared on the forum, thank you for sharing it. I tried to modify it to allow plotting in the expansion area but haven't gotten that to work. Can you advise if there is a way to easily make it plot only in the expansion area?
I simplified the code to plot OR high/low/mid on the expansion area. There is an input to set how many expansion bars you have on your chart (default is 5 bars). Hopefully this gets you started in the event there are more things you would like to add.

Ruby:
# Opening Range on expansion
# Created by @tony_futures

declare hide_on_daily;
input displayType = { "At timed start", default  "From RTH Start"};
input startTime = 0930;
input End_Time = 0945;
def RTH;

switch (displayType)
{
    case "At Timed Start":
      RTH = secondsFromTime(startTime) >= 0;
      
    case "From RTH Start":
      RTH = GetTime() >= RegularTradingStart(GetYYYYMMDD());

}

def Today = GetLastDay() == GetDay();
def ORActive = RTH and SecondsFromTime(End_Time) < 0;

def ORhigh = if RTH and !RTH[1] then high else if RTH and ORActive and high > ORhigh[1] then high else ORhigh[1];
def ORlow = if RTH and !RTH[1] then low else if RTH and ORActive and low < ORlow[1] then low else ORlow[1];

def ORFullRange = AbsValue(ORHigh - ORLow);
def midPoint = ORLow + (ORFullRange/2);

# setup Colors
DefineGlobalColor("midColor", CreateColor(132, 76, 130));
DefineGlobalColor("rangeColor", CreateColor(28, 96, 109));

#
input expansionBars = 5;
def OREnded = RTH and SecondsFromTime(End_Time) >= 0;
plot ORL = if isNaN(close) then ORlow[expansionBars] else Double.NaN;
ORL.SetDefaultColor(GlobalColor("rangeColor"));
ORL.HideBubble();
plot ORH = if isNaN(close) then ORhigh[expansionBars] else Double.NaN;
ORH.SetDefaultColor(GlobalColor("rangeColor"));
ORH.HideBubble();
input showMidPoint = yes;

plot mid = if isNaN(close) then midPoint[expansionBars] else Double.NaN;
mid.setDefaultColor(GlobalColor("midColor"));
mid.HideBubble();
 
I simplified the code to plot OR high/low/mid on the expansion area. There is an input to set how many expansion bars you have on your chart (default is 5 bars). Hopefully this gets you started in the event there are more things you would like to add.

Ruby:
# Opening Range on expansion
# Created by @tony_futures

declare hide_on_daily;
input displayType = { "At timed start", default  "From RTH Start"};
input startTime = 0930;
input End_Time = 0945;
def RTH;

switch (displayType)
{
    case "At Timed Start":
      RTH = secondsFromTime(startTime) >= 0;
     
    case "From RTH Start":
      RTH = GetTime() >= RegularTradingStart(GetYYYYMMDD());

}

def Today = GetLastDay() == GetDay();
def ORActive = RTH and SecondsFromTime(End_Time) < 0;

def ORhigh = if RTH and !RTH[1] then high else if RTH and ORActive and high > ORhigh[1] then high else ORhigh[1];
def ORlow = if RTH and !RTH[1] then low else if RTH and ORActive and low < ORlow[1] then low else ORlow[1];

def ORFullRange = AbsValue(ORHigh - ORLow);
def midPoint = ORLow + (ORFullRange/2);

# setup Colors
DefineGlobalColor("midColor", CreateColor(132, 76, 130));
DefineGlobalColor("rangeColor", CreateColor(28, 96, 109));

#
input expansionBars = 5;
def OREnded = RTH and SecondsFromTime(End_Time) >= 0;
plot ORL = if isNaN(close) then ORlow[expansionBars] else Double.NaN;
ORL.SetDefaultColor(GlobalColor("rangeColor"));
ORL.HideBubble();
plot ORH = if isNaN(close) then ORhigh[expansionBars] else Double.NaN;
ORH.SetDefaultColor(GlobalColor("rangeColor"));
ORH.HideBubble();
input showMidPoint = yes;

plot mid = if isNaN(close) then midPoint[expansionBars] else Double.NaN;
mid.setDefaultColor(GlobalColor("midColor"));
mid.HideBubble();

This will allow you to choose to plot these only in expansion area offset by how many bars you input at expansionbars.

Screenshot 2024-01-08 073550.png
Code:
# Opening Range on expansion
# Created by @tony_futures

declare hide_on_daily;
input show_on_expansion_only = yes;
input displayType = { "At timed start", default  "From RTH Start"};
input startTime = 0930;
input End_Time = 0945;
def RTH;

switch (displayType)
{
    case "At Timed Start":
      RTH = secondsFromTime(startTime) >= 0;
      
    case "From RTH Start":
      RTH = GetTime() >= RegularTradingStart(GetYYYYMMDD());

}

def Today = GetLastDay() == GetDay();
def ORActive = if isnan(close) then ORActive[1] else RTH and SecondsFromTime(End_Time) < 0;

def ORhigh = if isnan(close) then ORhigh[1] else if RTH and !RTH[1] then high else if RTH and ORActive and high > ORhigh[1] then high else ORhigh[1];
def ORlow = if isnan(close) then ORLow[1] else if RTH and !RTH[1] then low else if RTH and ORActive and low < ORlow[1] then low else ORlow[1];

def ORFullRange = AbsValue(ORHigh - ORLow);
def midPoint = ORLow + (ORFullRange/2);

# setup Colors
DefineGlobalColor("midColor", CreateColor(132, 76, 130));
DefineGlobalColor("rangeColor", CreateColor(28, 96, 109));

#
input expansionBars = 5;
def OREnded = RTH and SecondsFromTime(End_Time) >= 0;
plot ORL = if show_on_expansion_only and !isNaN(close[expansionbars]) then double.nan else ORlow[expansionbars];
ORL.SetDefaultColor(GlobalColor("rangeColor"));
ORL.setpaintingStrategy(paintingStrategy.HORIZONTAL);
ORL.HideBubble();
plot ORH = if show_on_expansion_only and !isNaN(close[expansionbars]) then double.nan else ORhigh[expansionbars];
ORH.SetDefaultColor(GlobalColor("rangeColor"));
ORH.setpaintingStrategy(paintingStrategy.HORIZONTAL);
ORH.HideBubble();
input showMidPoint = yes;

plot mid = if show_on_expansion_only and !isNaN(close[expansionbars]) then double.nan else midPoint[expansionBars];
mid.setDefaultColor(GlobalColor("midColor"));
mid.setpaintingStrategy(paintingStrategy.HORIZONTAL);
mid.HideBubble();
 
This will allow you to choose to plot these only in expansion area offset by how many bars you input at expansionbars.

Thanks so much. Will share the code with the range extensions added to save others some time since I went ahead and did that:

Code:
# Opening Range on expansion
# Created by @tony_futures

declare hide_on_daily;
input show_on_expansion_only = yes;
input displayType = { default "At timed start",  "From RTH Start"};
input startTime = 0930;
input End_Time = 1000;
def RTH;

switch (displayType)
{
    case "At Timed Start":
      RTH = secondsFromTime(startTime) >= 0;
      
    case "From RTH Start":
      RTH = GetTime() >= RegularTradingStart(GetYYYYMMDD());

}

def Today = GetLastDay() == GetDay();
def ORActive = if isnan(close) then ORActive[1] else RTH and SecondsFromTime(End_Time) < 0;

def ORhigh = if isnan(close) then ORhigh[1] else if RTH and !RTH[1] then high else if RTH and ORActive and high > ORhigh[1] then high else ORhigh[1];
def ORlow = if isnan(close) then ORLow[1] else if RTH and !RTH[1] then low else if RTH and ORActive and low < ORlow[1] then low else ORlow[1];

def ORFullRange = AbsValue(ORHigh - ORLow);
def midPoint = ORLow + (ORFullRange/2);

# setup Colors
DefineGlobalColor("quarterColor", CreateColor(169, 169, 169));
DefineGlobalColor("midColor", CreateColor(132, 76, 130));
DefineGlobalColor("rangeColor", CreateColor(28, 96, 109));
DefineGlobalColor("openColor", CreateColor(109, 84, 44));
DefineGlobalColor("downColor", CreateColor(109, 42, 28));
DefineGlobalColor("upColor", CreateColor(76, 133, 78));
#DefineGlobalColor("vwapColor", CreateColor(174, 157, 50));

input lineweight = 5;

#
input expansionBars = 8;
def OREnded = RTH and SecondsFromTime(End_Time) >= 0;
plot ORL = if show_on_expansion_only and !isNaN(close[expansionbars]) then double.nan else ORlow[expansionbars];
ORL.AssignValueColor(GlobalColor("rangeColor"));
ORL.setpaintingStrategy(paintingStrategy.HORIZONTAL);
ORL.HideBubble();
ORL.setlineweight(lineweight);
plot ORH = if show_on_expansion_only and !isNaN(close[expansionbars]) then double.nan else ORhigh[expansionbars];
ORH.AssignValueColor(GlobalColor("rangeColor"));
ORH.setpaintingStrategy(paintingStrategy.HORIZONTAL);
ORH.HideBubble();
input showMidPoint = yes;
ORH.setlineweight(lineweight);
plot mid = if show_on_expansion_only and !isNaN(close[expansionbars]) then double.nan else midPoint[expansionBars];
mid.AssignValueColor(GlobalColor("midColor"));
mid.setpaintingStrategy(paintingStrategy.HORIZONTAL);
mid.HideBubble();
mid.setlineweight(lineweight);

#

input showQuarters = no;
def oneQuarter = ORLow + (ORFullRange/4);
def threeQuarter = ORHigh - (ORFullRange/4);
plot oneQLine = if showQuarters and show_on_expansion_only and !isNaN(close[expansionbars]) then double.nan else oneQuarter[expansionBars];
oneQLine.AssignValueColor(GlobalColor("quarterColor"));
oneQLine.HideBubble();
oneQLine.setlineweight(lineweight);
plot threeQLine = if showQuarters and show_on_expansion_only and !isNaN(close[expansionbars]) then double.nan else threeQuarter[expansionBars];
threeQLine.AssignValueColor(GlobalColor("quarterColor"));
threeQLine.HideBubble();
threeQLine.setlineweight(lineweight);

input showMeasuredTargets = yes;
def upperTarget = (ORHigh + (ORFullRange/2));
plot upper = if showMeasuredTargets and show_on_expansion_only and !isNaN(close[expansionbars]) then double.nan else upperTarget[expansionBars];
upper.AssignValueColor(GlobalColor("upColor"));
upper.HideBubble();
upper.setlineweight(lineweight);
def lowerTarget = (ORLow - (ORFullRange/2));
plot lower = if showMeasuredTargets and show_on_expansion_only and !isNaN(close[expansionbars]) then double.nan else lowerTarget[expansionBars];
lower.AssignValueColor(GlobalColor("downColor"));
lower.HideBubble();
lower.setlineweight(lineweight);
input showMeasuredTargets2 = yes;
def upperTarget2 = (ORHigh + (ORFullRange));
plot upper2 = if showMeasuredTargets2 and show_on_expansion_only and !isNaN(close[expansionbars]) then double.nan else upperTarget2[expansionBars];
upper2.AssignValueColor(GlobalColor("upColor"));
upper2.HideBubble();
upper2.setlineweight(lineweight);
def lowerTarget2 = (ORLow - (ORFullRange));
plot lower2 = if showMeasuredTargets2 and show_on_expansion_only and !isNaN(close[expansionbars]) then double.nan else lowerTarget2[expansionBars];
lower2.AssignValueColor(GlobalColor("downColor"));
lower2.HideBubble();
lower2.setlineweight(lineweight);
 

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