Hello, and thank you very much for any help you may be able to offer!
I'm trying to use a variable (# of bars since last high/low based on ZigZag) to check back to see if the trend has changed (MA changed directions) since the last high/low. I have everything working except how to check <within a variable>.
The DidChange function is what I need.
I'm getting the error:
Only constants expected here: BarCount CL constant function parameter 'length' at 43:36
Code:
#counts bars since last Cycle High/Low
def NewCycle = close[1] == zzoth1;
def BarCount = if NewCycle then 1 else BarCount[1] + 1;
AddLabel (debug, "Bars Since last wave: " + BarCount);
def TrendChange = SMA[1] > SMA[2] and SMA < SMA[1] or SMA[1] < SMA[2] and SMA > SMA[1];
def DidChange = TrendChange within BarCount bars;
AddLabel(debug, "DidChange: " + DidChange);
Thank you again for looking at this and for your time thinking about it.
Thinkscript doesn't like variables for lengths. I've never found a good work around. Just a limitation we live with for the rest of the good of ToS charting.
if you are looking for true/false within a reasonable number of days, you can do a long if else if else if else if ... else chain where you look day by day through the ifs, but I wouldn't go overboard on that one for reasons of processor cycles. and it just gets annoying to debug. ;-)
You can also use brackets that way (days > 5 and days <= 10, days > 10 and days <= 15, etc...)
Maybe I can store the number of bars since last high/low and the number of bars since the last trend change and create DidChange function based on if high/low is greater than trend change!
Hello, and thank you very much for any help you may be able to offer!
I'm trying to use a variable (# of bars since last high/low based on ZigZag) to check back to see if the trend has changed (MA changed directions) since the last high/low. I have everything working except how to check <within a variable>.
The DidChange function is what I need.
I'm getting the error:
Only constants expected here: BarCount CL constant function parameter 'length' at 43:36
Code:
#counts bars since last Cycle High/Low
def NewCycle = close[1] == zzoth1;
def BarCount = if NewCycle then 1 else BarCount[1] + 1;
AddLabel (debug, "Bars Since last wave: " + BarCount);
def TrendChange = SMA[1] > SMA[2] and SMA < SMA[1] or SMA[1] < SMA[2] and SMA > SMA[1];
def DidChange = TrendChange within BarCount bars;
AddLabel(debug, "DidChange: " + DidChange);
Thank you again for looking at this and for your time thinking about it.
if you are counting bars after a zigzag signal, then looking to see if something happened during that count, it's the same as did something happen after the last zigzag signal. the count is irrelevant.
every time that a ma reverse occurs, it will be within the counter.
if you asked, did the ma trend change 6 bars after a zigzag reversal, that would be different. then a count would be useful.
it seems you are looking to see when a ma trend reversed, and maybe how many.
--------------------------
i made a study that counts ma (moving average) reversals, between zigzag peaks and valleys.
i started with your partial code, but ended up not using it. i added a zigzag code and an average code.
. draws lines from the zigzag peaks and valleys.
. draw an average line
. draw colored points on the ma line, to indicate when a reversal happens.
there are 4 test bubbles to show different values.
test1 - shows ma reversal counts, between zigzag peaks and valleys
one of the test bubbles shows barnumbers.
barnumbers of ma trend changes and zigzag reversals could be saved and compared, to determine when something happened.
Ruby:
# trend_chg_after_zigzag_00b
def bn = barnumber();
def na = double.nan;
# -------------------------------------
# https://usethinkscript.com/threads/zigzag-high-low-stats-for-thinkorswim.1073/page-6#post-90105
# ZigZag High Low Stats for ThinkorSwim
# post117
input Period = AggregationPeriod.FIFTEEN_MIN;
input method = {default average, high_low};
def bubbleoffset = .0005;
def percentamount = .01;
def revAmount = .05;
def atrreversal = 2.0;
def atrlength = 5;
def pricehigh = high(period = Period);
def pricelow = low(period = Period);
def averagelength = 5;
def averagetype = AverageType.EXPONENTIAL;
def mah = MovingAverage(averagetype, pricehigh, averagelength);
def mal = MovingAverage(averagetype, pricelow, averagelength);
def priceh = if method == method.high_low then pricehigh else mah;
def pricel = if method == method.high_low then pricelow else mal;
def zzhl = ZigZagHighLow("price h" = priceh, "price l" = pricel, "percentage reversal" = percentamount, "absolute reversal" = revAmount, "atr length" = atrlength, "atr reversal" = atrreversal);
# bn of zz peaks and valleys
def zzchg_bn = if bn == 1 then 0
else if !isnan(zzhl) then bn
else zzchg_bn[1];
# price of zz peaks and valleys
def zzchg_price = if bn == 1 then 0
else if !isnan(zzhl) then round(zzhl,2)
else zzchg_price[1];
# direction of zz lines
# =1 then dip, rev going up
# =0 then peak, rev going down
def zzdir = if bn == 1 then 0
else if (!isnan(zzhl) and zzchg_price[1] > zzchg_price) then 1
else if (!isnan(zzhl) and zzchg_price[1] < zzchg_price) then 0
else zzdir[1];
# -----------------------------------
input avg1_len = 30;
input avg1_type = AverageType.simple;
def ma1 = MovingAverage(avg1_type, close, avg1_len);
def sma = ma1;
plot maline = ma1;
maline.setdefaultcolor(color.magenta);
# chg so it looks at future bar
def matrend =
if bn == 1 then 0
else if ma1 < ma1[-1] then 1
else if ma1 > ma1[-1] then -1
else 0;
def marev = if bn == 1 then 0
else if matrend != matrend[1] then 1
else 0;
def machg_bn = if bn == 1 then 0
else if matrend != matrend[1] then bn
else machg_bn[1];
input ma_trend_change_points = yes;
plot maup = if (ma_trend_change_points and matrend != matrend[1] and matrend == 1) then ma1 else na;
maup.SetPaintingStrategy(PaintingStrategy.POINTS);
#maup.SetPaintingStrategy(PaintingStrategy.BOOLEAN_WEDGE_up);
maup.SetDefaultColor(Color.green);
maup.setlineweight(4);
maup.hidebubble();
plot madwn = if (ma_trend_change_points and matrend != matrend[1] and matrend == -1) then ma1 else na;
madwn.SetPaintingStrategy(PaintingStrategy.POINTS);
#madwn.SetPaintingStrategy(PaintingStrategy.BOOLEAN_WEDGE_DOWN);
madwn.SetDefaultColor(Color.red);
madwn.setlineweight(4);
madwn.hidebubble();
# --------------------------------------
input draw_zz_lines = yes;
plot zz1 = if draw_zz_lines then zzhl else na;
zz1.EnableApproximation();
zz1.setdefaultcolor(color.gray);
# ------------------------------------
# ------------------------------------
# original code . not used
#counts bars since last Cycle High/Low
#def NewCycle = close[1] == zzoth1;
def newcycle = !isnan(zzhl);
# count bars after zz rev
def BarCount = if NewCycle then 1 else BarCount[1] + 1;
AddLabel (1, "Bars Since last wave: " + BarCount);
#def TrendChange = SMA[1] > SMA[2] and SMA < SMA[1] or SMA[1] < SMA[2] and SMA > SMA[1];
#def DidChange = TrendChange within BarCount bars;
def DidChange = marev;
#AddLabel(1, "DidChange: " + DidChange);
# ------------------------------------
# ------------------------------------
#count count ma revs , and have the total on the zigzag bar
def marevcnt = if !isnan(zzhl[1]) then marev
else if marev then marevcnt[1] + 1
else marevcnt[1];
#then on the bar after the zigzag, reset cnt to 0 , unless a ma rev
input test1_ma_reverse_count = yes;
def en1 = if test1_ma_reverse_count and !isnan(zzhl) then 1 else 0;
addchartbubble(en1, zzhl,
#round(zzhl,2) + " zz\n" +
"ma cnt\n" +
marevcnt
, ( if marevcnt > 0 then color.magenta else color.gray)
, (if zzdir then no else yes));
input test2_zzhl_bubbles = no;
addchartbubble(test2_zzhl_bubbles, zzhl,
zzhl,
( if !isnan(zzhl) then color.yellow else color.gray), (if zzdir then no else yes));
input test3_zzdir_bubbles = no;
addchartbubble(test3_zzdir_bubbles, low,
zzchg_price + " zz $\n" +
zzdir + " zzdir"
, color.yellow, no);
#addlabel(1, bn + " " + machg_bn + " " + BarCount, color.yellow);
input test4_bubbles_bar_cnts = no;
addchartbubble(test4_bubbles_bar_cnts, low*0.996,
bn + " bn\n" +
machg_bn + " ma bn\n" +
(bn - machg_bn) + " ma cnt\n" +
BarCount + " zz cnt"
, color.yellow, no);
#
test1 = yes , shows the count of ma reversals between zigzag peaks and valleys
if you are counting bars after a zigzag signal, then looking to see if something happened during that count, it's the same as did something happen after the last zigzag signal. the count is irrelevant.
every time that a ma reverse occurs, it will be within the counter.
if you asked, did the ma trend change 6 bars after a zigzag reversal, that would be different. then a count would be useful.
it seems you are looking to see when a ma trend reversed, and maybe how many.
--------------------------
i made a study that counts ma (moving average) reversals, between zigzag peaks and valleys.
i started with your partial code, but ended up not using it. i added a zigzag code and an average code.
. draws lines from the zigzag peaks and valleys.
. draw an average line
. draw colored points on the ma line, to indicate when a reversal happens.
there are 4 test bubbles to show different values.
test1 - shows ma reversal counts, between zigzag peaks and valleys
one of the test bubbles shows barnumbers.
barnumbers of ma trend changes and zigzag reversals could be saved and compared, to determine when something happened.
Ruby:
# trend_chg_after_zigzag_00b
def bn = barnumber();
def na = double.nan;
# -------------------------------------
# https://usethinkscript.com/threads/zigzag-high-low-stats-for-thinkorswim.1073/page-6#post-90105
# ZigZag High Low Stats for ThinkorSwim
# post117
input Period = AggregationPeriod.FIFTEEN_MIN;
input method = {default average, high_low};
def bubbleoffset = .0005;
def percentamount = .01;
def revAmount = .05;
def atrreversal = 2.0;
def atrlength = 5;
def pricehigh = high(period = Period);
def pricelow = low(period = Period);
def averagelength = 5;
def averagetype = AverageType.EXPONENTIAL;
def mah = MovingAverage(averagetype, pricehigh, averagelength);
def mal = MovingAverage(averagetype, pricelow, averagelength);
def priceh = if method == method.high_low then pricehigh else mah;
def pricel = if method == method.high_low then pricelow else mal;
def zzhl = ZigZagHighLow("price h" = priceh, "price l" = pricel, "percentage reversal" = percentamount, "absolute reversal" = revAmount, "atr length" = atrlength, "atr reversal" = atrreversal);
# bn of zz peaks and valleys
def zzchg_bn = if bn == 1 then 0
else if !isnan(zzhl) then bn
else zzchg_bn[1];
# price of zz peaks and valleys
def zzchg_price = if bn == 1 then 0
else if !isnan(zzhl) then round(zzhl,2)
else zzchg_price[1];
# direction of zz lines
# =1 then dip, rev going up
# =0 then peak, rev going down
def zzdir = if bn == 1 then 0
else if (!isnan(zzhl) and zzchg_price[1] > zzchg_price) then 1
else if (!isnan(zzhl) and zzchg_price[1] < zzchg_price) then 0
else zzdir[1];
# -----------------------------------
input avg1_len = 30;
input avg1_type = AverageType.simple;
def ma1 = MovingAverage(avg1_type, close, avg1_len);
def sma = ma1;
plot maline = ma1;
maline.setdefaultcolor(color.magenta);
# chg so it looks at future bar
def matrend =
if bn == 1 then 0
else if ma1 < ma1[-1] then 1
else if ma1 > ma1[-1] then -1
else 0;
def marev = if bn == 1 then 0
else if matrend != matrend[1] then 1
else 0;
def machg_bn = if bn == 1 then 0
else if matrend != matrend[1] then bn
else machg_bn[1];
input ma_trend_change_points = yes;
plot maup = if (ma_trend_change_points and matrend != matrend[1] and matrend == 1) then ma1 else na;
maup.SetPaintingStrategy(PaintingStrategy.POINTS);
#maup.SetPaintingStrategy(PaintingStrategy.BOOLEAN_WEDGE_up);
maup.SetDefaultColor(Color.green);
maup.setlineweight(4);
maup.hidebubble();
plot madwn = if (ma_trend_change_points and matrend != matrend[1] and matrend == -1) then ma1 else na;
madwn.SetPaintingStrategy(PaintingStrategy.POINTS);
#madwn.SetPaintingStrategy(PaintingStrategy.BOOLEAN_WEDGE_DOWN);
madwn.SetDefaultColor(Color.red);
madwn.setlineweight(4);
madwn.hidebubble();
# --------------------------------------
input draw_zz_lines = yes;
plot zz1 = if draw_zz_lines then zzhl else na;
zz1.EnableApproximation();
zz1.setdefaultcolor(color.gray);
# ------------------------------------
# ------------------------------------
# original code . not used
#counts bars since last Cycle High/Low
#def NewCycle = close[1] == zzoth1;
def newcycle = !isnan(zzhl);
# count bars after zz rev
def BarCount = if NewCycle then 1 else BarCount[1] + 1;
AddLabel (1, "Bars Since last wave: " + BarCount);
#def TrendChange = SMA[1] > SMA[2] and SMA < SMA[1] or SMA[1] < SMA[2] and SMA > SMA[1];
#def DidChange = TrendChange within BarCount bars;
def DidChange = marev;
#AddLabel(1, "DidChange: " + DidChange);
# ------------------------------------
# ------------------------------------
#count count ma revs , and have the total on the zigzag bar
def marevcnt = if !isnan(zzhl[1]) then marev
else if marev then marevcnt[1] + 1
else marevcnt[1];
#then on the bar after the zigzag, reset cnt to 0 , unless a ma rev
input test1_ma_reverse_count = yes;
def en1 = if test1_ma_reverse_count and !isnan(zzhl) then 1 else 0;
addchartbubble(en1, zzhl,
#round(zzhl,2) + " zz\n" +
"ma cnt\n" +
marevcnt
, ( if marevcnt > 0 then color.magenta else color.gray)
, (if zzdir then no else yes));
input test2_zzhl_bubbles = no;
addchartbubble(test2_zzhl_bubbles, zzhl,
zzhl,
( if !isnan(zzhl) then color.yellow else color.gray), (if zzdir then no else yes));
input test3_zzdir_bubbles = no;
addchartbubble(test3_zzdir_bubbles, low,
zzchg_price + " zz $\n" +
zzdir + " zzdir"
, color.yellow, no);
#addlabel(1, bn + " " + machg_bn + " " + BarCount, color.yellow);
input test4_bubbles_bar_cnts = no;
addchartbubble(test4_bubbles_bar_cnts, low*0.996,
bn + " bn\n" +
machg_bn + " ma bn\n" +
(bn - machg_bn) + " ma cnt\n" +
BarCount + " zz cnt"
, color.yellow, no);
#
test1 = yes , shows the count of ma reversals between zigzag peaks and valleys
Thank you so much, Halcyoguy! I definitely be able to improve my code with this!
Would you happen to know how to get the newest ZigZag wave high to only count if the low of the wave high candle low is completely above the previous wave high candle high?
I've tried, with mediocre results (it doesn't work really). I subtract 1 on a failed wave (low isn't above close of previous high) which works to keep the count I want, but I can't properly define a failed wave.
#def failed wave high/low
def FailedWave = SMA > SMA[1] and zzoth > zzoth[1] and zzoth <= zzoth2 or SMA < SMA[1] and zzoth < zzoth[1] and zzoth >= zzoth2;
Then
def CycleCount = if DidChange then 1 else if !DidChange and FailedWave and zzoth != zzoth[1] then CycleCount[1] - 1 else if NewCycle then CycleCount[1] + 1 else CycleCount[1];
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.
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.