Chop Zone with Moving Average For ThinkOrSwim

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

CSS:
// Chopzone indicator code on TradingView - as below

// This source code provided free and open-source as defined by the terms of the Mozilla Public License 2.0 (https://mozilla.org/MPL/2.0/)
// with the following additional requirements:
//
// 1. Citations for sources and references must be maintained and updated when appropriate
// 2. Links to strategy references included in indicator tooptips and/or alerts should be retained to give credit to the original source
//             while also providing a freely available source of information on proper use and interpretation
//
// Author:  SamAccountX
//
// Original inspiration came from the built-in Chop Zone indicator (https://www.tradingview.com/chart/?solution=43000589111),
// however I wanted to make some improvements and add some customization options to better suit varying market conditions.
//
// WARNING: Please be sure of what you're doing and understand the potential implications before altering any of the settings
//          in the "Advanced Configuration" section!!!
//
//@version=5
indicator(title = "Chop Zone - SamX", format=format.price, precision=2, max_labels_count=500)
// ***  Inputs  ***
// Basic input settings
g_NormalInputs = 'Basic Configuration'
tf = input.timeframe(title="Timeframe", defval="", group=g_NormalInputs)
showGaps = input.bool(title="Show gaps for higher timeframes", defval=true, group=g_NormalInputs, tooltip="If selected, higher TF values will only be returned when " +
         'the higher timeframe bar actually closes.  This helps avoid real-time repaining at the expense of potential resolution clarity. \n\n' +
         'If this option is unchecked, the current bar will be populated with the current higher TF bar\'s value (which will repaint), however ' +
         'historical bars will not repaint.')
src = input.source(title='MA Source', defval=close, group=g_NormalInputs, tooltip="Price source to use for calculating the MA basis for the chop zones.")
len = input.int(title='MA Length', defval=34, minval=1, maxval=500, step=1, group=g_NormalInputs, tooltip="Length to use for calculating the MA basis for the chop zones.")
showAsAngleArea = input.bool(title="Plot calculated angle", defval=false, group=g_NormalInputs, tooltip="If selected, the default bar-style chop zone will be replaced with an " +
         'Area-style chart displaying the actual calculated angles. \n\n' +
         'Note #1:  This works best using the Gradient color settings below. \n\n' +
         'Note #2:  If configured to calculate on a timeframe HIGHER than the current chart timeframe, it is recommended to un-check the "Show gaps for higher timeframes" setting above ' +
         'to avoid display anomolies.')
// Coloring settings
// Gradient settings
g_GradientSettings = "Gradient Color Settings"
colorAsGradient = input.bool(title="Color bars using gradient", defval=false, group=g_GradientSettings)
downColor = input.color(title="Downslope:", defval=color.rgb(255, 0, 0, 0), inline="Gradient", group=g_GradientSettings)
upColor = input.color(title="         Upslope:", defval=color.rgb(0, 255, 0, 0), inline="Gradient", group=g_GradientSettings)
gradientLimit = input.int(title="Gradient Limit", defval=33, minval=1, maxval=89, step=1, group=g_GradientSettings, tooltip="Select the desired gradient threshold angle. This " +
         'will be used in gradient color calculations.  This value will be extrapolated as the absolute distance from 0.  If the calculated angle exceeds this threshold, the resulting ' +
         'bar color will be the equivilent of the closest in-range color.')
// Fixed bar color settings
g_BarColors = 'Bar colors'
// Tier 0 - centered on 0 degrees
colorLevel0 = input.color(title="                       Tier-1 Color:", defval=color.rgb(253, 216, 53, 0), group=g_BarColors)
// Tier 1 - 1x past tier 0
colorLevel1Pos = input.color(title="Tier-2 Color - Positive:", defval=color.rgb(0, 150, 136, 0), group=g_BarColors, inline="tier-2")
colorLevel1Neg = input.color(title="   Negative:", defval=color.rgb(255, 183, 77, 0), group=g_BarColors, inline="tier-2")
// Tier 2 - 1x past tier 1
colorLevel2Pos = input.color(title="Tier-3 Color - Positive:", defval=color.rgb(165, 214, 167, 0), group=g_BarColors, inline="tier-3")
colorLevel2Neg = input.color(title="   Negative:", defval=color.rgb(255, 109, 0, 0), group=g_BarColors, inline="tier-3")
// Tier 3 - 1x past tier 2
colorLevel3Pos = input.color(title="Tier-4 Color - Positive:", defval=color.rgb(67, 160, 71, 0), group=g_BarColors, inline="tier-4")
colorLevel3Neg = input.color(title="   Negative:", defval=color.rgb(233, 30, 99, 0), group=g_BarColors, inline="tier-4")
// Tier 4 - 1x past tier 3
colorLevel4Pos = input.color(title="Tier-5 Color - Positive:", defval=color.rgb(38, 198, 218, 0), group=g_BarColors, inline="tier-5")
colorLevel4Neg = input.color(title="   Negative:", defval=color.rgb(213, 0, 0, 0), group=g_BarColors, inline="tier-5")
//
// Advanced input settings - generally should not be changed...
g_AdvancedInputs = 'Advanced Configuration'
maType = input.string(title='Moving Average Calculation', group=g_AdvancedInputs, options=['Exponential', 'Simple', 'Smoothed', 'Weighted', 'Linear', 'Hull', 'Volume-Weigehted', 'RMA', 'ALMA'],
           defval='Exponential', tooltip='Type of moving average calculation to use (default is Exponential (EMA)). ALMA uses the standard values for sigma and offset.  \n\n' +
                  'Note: DO NOT CHANGE THIS UNLESS YOU KNOW WHAT YOU\'RE DOING!!!')
periodsIn = input.int(title='Periods', defval=30, minval=1, maxval=300, step=1, group=g_AdvancedInputs, tooltip='Number of candles to check when searching for highest high and lowest low.  \n\n' +
             'Note: DO NOT CHANGE THIS UNLESS YOU KNOW WHAT YOU\'RE DOING!!!')
spanFactor = input.int(title='Span Length', defval=25, minval=1, maxval=100, step=1, group=g_AdvancedInputs, tooltip='Span length for range calculations. \n\n' +
             'Note: DO NOT CHANGE THIS UNLESS YOU KNOW WHAT YOU\'RE DOING!!!')
periodAvgSrc = input.string(title='Period/Bar Average', defval="hlc3", options=["hl2", "hlc3", "ohlc4", "hlcc4"], tooltip='Method to use to derive the average price for a ' +
             'given bar for use in slope calculations. \n\n' +
             'Note: DO NOT CHANGE THIS UNLESS YOU KNOW WHAT YOU\'RE DOING!!!')
stepSize = input.float(title="Bar Step Size", defval=1.43, minval=.01, maxval=10, step=0.1, group=g_AdvancedInputs, tooltip='Step size to use for chop zone brackets.  Increasing this will result ' +
             'in each bar covering a wider range of angles, while decreasing this will result in each bar covering a narrower range of angles.')
useAltSlopeCalc = input.bool(title='Use alternate slope calculation method', defval=false, group=g_AdvancedInputs, tooltip='Select this to find the MA slope using an alternate calculation method. \n\n' +
             'Note: DO NOT CHANGE THIS UNLESS YOU KNOW WHAT YOU\'RE DOING!!!')
//
// ***  Function definitions  ***
// Smoothed MA
smoothedMovingAvg(src, len) =>
    smma = 0.0
    // TV will complain about the use of the ta.sma function use inside a function saying that it should be called on each calculation,
    // but since we're only using it once to set the initial value for the smoothed MA (when the previous smma value is NaN - Not a Number)
    // and using the previous smma value for each subsequent iteration, this can be safely ignored
    smma := na(smma[1]) ? ta.sma(src, len) : (smma[1] * (len - 1) + src) / len
    smma
//
// MA calculation
ma(source, length, type) =>
    switch type
        "Simple" => ta.sma(source, length)
        "Exponential" => ta.ema(source, length)
        "Weighted" => ta.wma(source, length)
        "Volume-Weigehted" => ta.vwma(source, length)
        "Smoothed" => smoothedMovingAvg(source, length)
        "RMA" => ta.rma(source, length)
        "Linear" => ta.linreg(source, length, 0)
        "Hull" => ta.hma(source, length)
        "ALMA" => ta.alma(source, length, 0.85, 6)
//
//  *** Functional code start  ***
//
// Explicitly define our ticker to help ensure that we're always getting ACTUAL price instead of relying on the input
// ticker info and input vars (as they tend to inherit the type from what's displayed on the current chart)
realPriceTicker = ticker.new(prefix=syminfo.prefix, ticker=syminfo.ticker)

avgCalc = switch periodAvgSrc
    "hl2" => hl2
    "hlc3" => hlc3
    "ohlc4" => ohlc4
    "hlcc4" => hlcc4
    => hlc3
   
avg = showGaps ? request.security(symbol=realPriceTicker, timeframe=tf, expression=avgCalc, lookahead=barmerge.lookahead_off, gaps=barmerge.gaps_on) :
                 request.security(symbol=realPriceTicker, timeframe=tf, expression=avgCalc, lookahead=barmerge.lookahead_off, gaps=barmerge.gaps_off)
pi = math.pi
periods = periodsIn
highestHigh = showGaps ? request.security(symbol=realPriceTicker, timeframe=tf, expression=ta.highest(periods), lookahead=barmerge.lookahead_off, gaps=barmerge.gaps_on) :
                         request.security(symbol=realPriceTicker, timeframe=tf, expression=ta.highest(periods), lookahead=barmerge.lookahead_off, gaps=barmerge.gaps_off)
lowestLow = showGaps ? request.security(symbol=realPriceTicker, timeframe=tf, expression=ta.lowest(periods), lookahead=barmerge.lookahead_off, gaps=barmerge.gaps_on) :
                     request.security(symbol=realPriceTicker, timeframe=tf, expression=ta.lowest(periods), lookahead=barmerge.lookahead_off, gaps=barmerge.gaps_off)
span = spanFactor / (highestHigh - lowestLow) * lowestLow
ema34 = showGaps ? request.security(symbol=realPriceTicker, timeframe=tf, expression=ma(src, len, maType), lookahead=barmerge.lookahead_off, gaps=barmerge.gaps_on) :
                   request.security(symbol=realPriceTicker, timeframe=tf, expression=ma(src, len, maType), lookahead=barmerge.lookahead_off, gaps=barmerge.gaps_off)
ema34_prev = showGaps ? request.security(symbol=realPriceTicker, timeframe=tf, expression=ma(src[1], len, maType), lookahead=barmerge.lookahead_off, gaps=barmerge.gaps_on) :
                         request.security(symbol=realPriceTicker, timeframe=tf, expression=ma(src[1], len, maType), lookahead=barmerge.lookahead_off, gaps=barmerge.gaps_off)

var emaAngle = 0.0
if (useAltSlopeCalc)
    rightX = 1
    rightY = ema34
    leftX = 0
    leftY = ema34_prev
    slope = (rightY - leftY) / (rightX - leftX)
    angleRadians = math.atan(slope)
    angleDegrees = math.todegrees(angleRadians)
    emaAngle := angleDegrees //slope < 0 ? -angleDegrees : angleDegrees
else
    x1_ema34 = 0
    x2_ema34 = 1
    y1_ema34 = 0
    y2_ema34 = (ema34_prev - ema34) / avg * span
    c_ema34 = math.sqrt((x2_ema34 - x1_ema34)*(x2_ema34 - x1_ema34) + (y2_ema34 - y1_ema34)*(y2_ema34 - y1_ema34))
    emaAngle_1 = math.round(180 * math.acos((x2_ema34 - x1_ema34)/c_ema34) / pi)
    emaAngle := y2_ema34 > 0 ? -emaAngle_1 : emaAngle_1
   
// Select color based on inputs and calculated MA angle...
//
// First, we need to calculate our 0-level zone.  Since we need to also include the ACTUAL 0.00 angle as well, we
// have a few options for sizing this zone...  For simplicity, we're going to divide our bar step size by 2 and
// round to 2 decimal places.  Should rounding be required, we'll always round down.
//
// Unfortunately, TV doesn't have a `floor` function that can round to decimals (only integers), so we'll have to
// use some clever math gymnastics to accomplish this.
halfStep = math.floor((stepSize / 2) * 100) / 100
var color chopZoneColor = na
if (emaAngle >= 3*stepSize + halfStep)
    chopZoneColor := colorLevel4Pos
else if (emaAngle < 3*stepSize + halfStep and emaAngle >= 2*stepSize + halfStep)
    chopZoneColor := colorLevel3Pos
else if (emaAngle < 2*stepSize + halfStep and emaAngle >= stepSize + halfStep)
    chopZoneColor := colorLevel2Pos
else if (emaAngle < stepSize + halfStep and emaAngle >= halfStep)
    chopZoneColor := colorLevel1Pos
else if (emaAngle > -halfStep and emaAngle < halfStep)
    // Between -.71 and .71
    chopZoneColor := colorLevel0
else if (emaAngle > -stepSize - halfStep and emaAngle <= -halfStep)
    chopZoneColor := colorLevel1Neg
else if (emaAngle > -2*stepSize - halfStep and emaAngle <= -stepSize - halfStep)
    chopZoneColor := colorLevel2Neg
else if (emaAngle > -3*stepSize - halfStep and emaAngle <= -2*stepSize - halfStep)
    chopZoneColor := colorLevel3Neg
else if (emaAngle <= -3*stepSize - halfStep)
    chopZoneColor := colorLevel4Neg

if (colorAsGradient)
    chopZoneColor := color.from_gradient(emaAngle, -gradientLimit, gradientLimit, downColor, upColor)


plot(showAsAngleArea ? na : 1, title='Chop Zone', color=na(avg) ? na : chopZoneColor, style=plot.style_columns)
plot(showAsAngleArea ? emaAngle : na, title='MA Angle', color=na(avg) ? na : chopZoneColor, style=plot.style_area)
// Label plots - for testing use only
//if not na(avg)
//    label.new(bar_index, 1.25, text=str.tostring(math.round(emaAngle)), style=label.style_label_down)

https://www.tradingview.com/script/8IaHOdPX-Chop-Zone-SamX/

To get to the code you can use above link - add the indicator to your TV chart -- and click on code link - to see the code - but otherwise I have added for you above.
try this may be sufficient

CSS:
#https://www.tradingview.com/script/P9T0GyBA-Chop-Zone-with-Moving-Average/
#@Senor_Puts
#indicator(title = "Chop Zone with Moving Average", format=format.price, precision=0, timeframe=""
# Converted by Sam4Cok@Samer800 - 11/2022
Declare Lower;
#--- Colors
DefineGlobalColor("colorTurquoise" , CreateColor(0,221,255));
DefineGlobalColor("colorDarkGreen" , CreateColor(4,188,217));
DefineGlobalColor("colorPaleGreen" , CreateColor(4,156,179));
DefineGlobalColor("colorLime" , CreateColor(4,127,145));

DefineGlobalColor("colorDarkRed" , CreateColor(216, 0, 255));
DefineGlobalColor("colorRed" , CreateColor(187,4,219));
DefineGlobalColor("colorOrange" , CreateColor(155,5,181));
DefineGlobalColor("colorLightOrange" , CreateColor(123,3,143));
DefineGlobalColor("colorYellow"   , Color.DARK_GRAY);
Input ColorBar = no;
def na = Double.NaN;
def source = close;
def avg = hlc3;
def pi = ATan(1) * 4;
def periods = 30;
def highestHigh = Highest(high, periods);
def lowestLow = Lowest(low, periods);
def span = 25 / (highestHigh - lowestLow) * lowestLow;
def ema34 = ExpAverage(source, 34);
def x1_ema34 = 0;
def x2_ema34 = 1;
def y1_ema34 = 0;
def y2_ema34 = (ema34[1] - ema34) / avg * span;
def c_ema34 = Sqrt((x2_ema34 - x1_ema34) * (x2_ema34 - x1_ema34) + (y2_ema34 - y1_ema34) * (y2_ema34 - y1_ema34));
def emaAngle_1 = Round(180 * ACos((x2_ema34 - x1_ema34) / c_ema34) / pi, 0);
def emaAngle = If(y2_ema34 > 0, - emaAngle_1, emaAngle_1);
def TrendUp = emaAngle >= 5;
def TrendDn = emaAngle <= -1 * 5;
def RevUp = TrendUp and TrendDn[1];
def RevDn = TrendDn and TrendUp[1];
plot "0" = if isNaN(close) then na else 0;
"0".SetPaintingStrategy(PaintingStrategy.SQUARED_HISTOGRAM);
"0".AssignValueColor(if emaAngle >= 5 then GlobalColor("colorTurquoise") else
                     if emaAngle < 5 and emaAngle >= 3.57 then GlobalColor("colorDarkGreen") else
                     if emaAngle < 3.57 and emaAngle >= 2.14 then GlobalColor("colorPaleGreen") else
                     if emaAngle < 2.14 and emaAngle >= .71 then GlobalColor("colorLime") else
                     if emaAngle <= -1 * 5 then GlobalColor("colorDarkRed") else
                     if emaAngle > -1 * 5 and emaAngle <= -1 * 3.57 then GlobalColor("colorRed") else
                     if emaAngle > -1 * 3.57 and emaAngle <= -1 * 2.14 then GlobalColor("colorOrange") else
                     if emaAngle > -1 * 2.14 and emaAngle <= -1 * .71 then GlobalColor("colorLightOrange") else
                        GlobalColor("colorYellow"));
plot "1" = if isNaN(close) then na else 1;#, color=chopZoneColor, style=plot.style_columns)
"1".SetPaintingStrategy(PaintingStrategy.SQUARED_HISTOGRAM);
"1".AssignValueColor(if emaAngle >= 5 then GlobalColor("colorTurquoise") else
                     if emaAngle < 5 and emaAngle >= 3.57 then GlobalColor("colorDarkGreen") else
                     if emaAngle < 3.57 and emaAngle >= 2.14 then GlobalColor("colorPaleGreen") else
                     if emaAngle < 2.14 and emaAngle >= .71 then GlobalColor("colorLime") else
                     if emaAngle <= -1 * 5 then GlobalColor("colorDarkRed") else
                     if emaAngle > -1 * 5 and emaAngle <= -1 * 3.57 then GlobalColor("colorRed") else
                     if emaAngle > -1 * 3.57 and emaAngle <= -1 * 2.14 then GlobalColor("colorOrange") else
                     if emaAngle > -1 * 2.14 and emaAngle <= -1 * .71 then GlobalColor("colorLightOrange") else
                        GlobalColor("colorYellow"));

AssignPriceColor(if !ColorBar then Color.CURRENT else
                 if RevUp then color.GREEN else
                 if RevDn then color.RED else
                 if emaAngle >= 5 then GlobalColor("colorTurquoise") else
                 if emaAngle < 5 and emaAngle >= 3.57 then GlobalColor("colorDarkGreen") else
                 if emaAngle < 3.57 and emaAngle >= 2.14 then GlobalColor("colorPaleGreen") else
                 if emaAngle < 2.14 and emaAngle >= .71 then GlobalColor("colorLime") else
                 if emaAngle <= -1 * 5 then GlobalColor("colorDarkRed") else
                 if emaAngle > -1 * 5 and emaAngle <= -1 * 3.57 then GlobalColor("colorRed") else
                 if emaAngle > -1 * 3.57 and emaAngle <= -1 * 2.14 then GlobalColor("colorOrange") else
                 if emaAngle > -1 * 2.14 and emaAngle <= -1 * .71 then GlobalColor("colorLightOrange") else
                        GlobalColor("colorYellow"));

plot SigUp = if RevUp then 1.1 else na;
plot SigDn = if RevDn then 1.1 else na;

SigUp.SetPaintingStrategy(PaintingStrategy.SQUARES);
SigUp.SetDefaultColor(Color.GREEN);
SigUp.SetLineWeight(3);

SigDn.SetPaintingStrategy(PaintingStrategy.SQUARES);
SigDn.SetDefaultColor(Color.RED);
SigDn.SetLineWeight(3);

#---- END CODE
 

Similar threads

Not the exact question you're looking for?

Start a new thread and receive assistance from our community.

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