mfox
Member
After someone recently commented on Cyclic RSI v1, I mentioned that I don't really trade anymore, and I'm too busy to do much Thinkscript'ing, but it made me start wondering about this script again. I was always disappointed with the fact that I couldn't get the DRO (dominant rhythm oscillator) working to dynamically set the lookback for the Cyclic RSI. So I did some digging...
I realized that if I was lucky, I could tweak the ZigZagHigh lows to count the bars between highs, and it might have already been out there somewhere, but I didn't find it, so I changed a script from Tomsk and got it working:
Eureka! An average cycle rounded to the nearest 10 (which I will eventually use to perform harmonic reduction on larger values, 40, 80, 120 all go to 40). So I plugged it into my script below, but I ran into a problem. All of my folds now break for some reason. If I read the label from the cycle above I might get exactly 30, in non-decimal form. This goes into a variable CyclicMemory which is domCycle * 2. However, when I started fold'ing, my script compiles, but won't render with the error: "Folding integer 'to' is expected. NaN". I know this has to do with data types and variable lengths, and in a lot of cases I had to break things like Highest() out to a fold to avoid the dreaded "CL constant function parameter 'length'" error. Here's my CyclicRSI v2 script below (assuming domCycle = output of script above), with clutter removed:
I honestly hope this is a simple mistake, I'll shoulder that shame no problem, I've just always wanted to get this indicator to be truly dynamic. You can see all the folds that go to "cyclicmemory -1" are where this error occurs, but they all seem fine to me. Naturally, if I hard code any integer to the cyclicmemory variable, the code works fine. Is there any possible workaround for this? It's literally the one thing stopping Cyclic RSI v2 from working.
I realized that if I was lucky, I could tweak the ZigZagHigh lows to count the bars between highs, and it might have already been out there somewhere, but I didn't find it, so I changed a script from Tomsk and got it working:
Code:
# ZigZag High Low Stats
# tomsk
# 11.16.2019
# V1.0 - 11.16.2019 - tomsk - Initial release of ZigZag High Low Stats
# Extracted idea from RDMercer's post #369 of a variant of a massive
# Zig Zag High Low Supply Demand study that comprises many different
# components
#
# https://usethinkscript.com/threads/trend-reversal-indicator-with-signals-for-thinkorswim.183/page-19#post-369
#
# I heavily modified, cleaned up and extracted some interesting Zig Zag statistical information resulting in this study called Zig Zag High
# Low Stats. It displays the following information represented via bubbles at each of the Zig zag turning points
#
# Label for Confirmed/Unconfirmed Status of Current Zigzag
# Price Change between Zigzags
# Price at Zigzag High/Low
# Bar Count between Zigzags
# Volume at Zigzag Reversals
# added by mfox
input dominantType = {default "Highs", "Lows"};
def cycleMode;
switch (dominantType) {
case "Highs":
cycleMode = 1;
case "Lows":
cycleMode = 2;
}
input BubbleOffset = .0005;
input PercentAmount = .01;
input RevAmount = .05;
input ATRreversal = 3.0;
input ATRlength = 5;
def zz = ZigZagHighLow("price h" = high, "price l" = low, "percentage reversal" = PercentAmount,
"absolute reversal" = RevAmount, "atr length" = ATRlength, "atr reversal" = ATRreversal);
def ReversalAmount = if (close * PercentAmount / 100) > Max(RevAmount < ATRreversal * reference ATR(ATRlength), RevAmount)
then (close * PercentAmount / 100)
else if RevAmount < ATRreversal * reference ATR(ATRlength)
then ATRreversal * reference ATR(ATRlength)
else RevAmount;
# Zig Zag Specific Data
plot zzz = zz;
zzz.EnableApproximation();
def zzSave = if !IsNaN(zz) then zz else GetValue(zzSave, 1);
def chg = (if zzSave == high then high else low) - GetValue(zzSave, 1);
def isUp = chg >= 0;
# Bar Count Specific Data
def zzCount = if zzSave[1] != zzSave then 1 else if zzSave[1] == zzSave then zzCount[1] + 1 else 0;
# Dom Count Specific Data - Added by mfox
def zzDomCount = if zzCount == 1 and isUp == (if cycleMode == 1 then yes else no) then 1 else zzDomCount[1] + 1;
def zzDomTotal = if zzCount == 1 and isUp == (if cycleMode == 1 then yes else no) then zzDomCount[1] else 0;
def zzCycles = zzCount == 1 and isUp == (if cycleMode == 1 then yes else no);
def cycleDoms = TotalSum(zzDomTotal);
def cycleCount = TotalSum(zzCycles);
plot dominantCycle = Round(((cycleDoms / cycleCount) / 10), 0) * 10;
dominantCycle.Hide();
AddLabel(yes, "Dominant Cycle: " + dominantCycle);
Eureka! An average cycle rounded to the nearest 10 (which I will eventually use to perform harmonic reduction on larger values, 40, 80, 120 all go to 40). So I plugged it into my script below, but I ran into a problem. All of my folds now break for some reason. If I read the label from the cycle above I might get exactly 30, in non-decimal form. This goes into a variable CyclicMemory which is domCycle * 2. However, when I started fold'ing, my script compiles, but won't render with the error: "Folding integer 'to' is expected. NaN". I know this has to do with data types and variable lengths, and in a lot of cases I had to break things like Highest() out to a fold to avoid the dreaded "CL constant function parameter 'length'" error. Here's my CyclicRSI v2 script below (assuming domCycle = output of script above), with clutter removed:
Code:
def src = close;
# change 1
# old
# input domcycle = 20; # Works fine
# new
def domcycle = dominantCycle;
def cyclelen = domcycle / 2;
def vibration = 10;
def leveling = 10.0;
def cyclicmemory = domcycle * 2;
def crsi = torque * (2 * rsi - rsi[phasingLag]) + (1 - torque) * (if IsNaN(crsi[1]) then 0 else crsi[1]);
# change 2
# old
# def lm_hist = if crsi > Highest(crsi, cyclicmemory - 1) and !IsNaN(lm_hist[1])
# then crsi
# else if -crsi < Lowest(crsi, cyclicmemory - 1) and !IsNaN(lm_hist[1])
# then -crsi
# else 0;
# new
def memHigh = fold hx = 0 to cyclicmemory -1 with lw = double.NEGATIVE_INFINITY do if high > lw then high else lw;
def memLow = fold lx = 0 to cyclicmemory -1 with hw = double.poSITIVE_INFINITY do if low < hw then low else hw;
def lm_hist = if crsi > memHigh and !IsNaN(lm_hist[1])
then crsi
else if -crsi < memLow and !IsNaN(lm_hist[1])
then -crsi
else 0;
# change 3
# old
#def lmax = -Highest(lm_hist, cyclicmemory -1);
#def lmin = -Lowest(lm_hist, cyclicmemory -1);
def lmax = - (fold lmx = 0 to cyclicmemory -1 with lwx = double.Negative_infinity do if GetValue(lm_hist, lmx) > lwx then GetValue(lm_hist, lmx) else lwx);
def lmin = - (fold lmn = 0 to cyclicmemory -1 with lwn = double.positive_infinity do if GetValue(lm_hist, lmn) < lwn then GetValue(lm_hist, lmn) else lwn);
def mstep = (lmax - lmin) / 100;
def aperc = leveling / 100;
# change 4
# problem: folding to "cyclicmemory - 1" now produces an error: Folding intenger "to" is expected. NaN
# ???
def db = fold dbx = 0 to 100
while (fold blx = 0 to cyclicmemory - 1
with b
do b + if GetValue(crsi, blx) < lmin + mstep * dbx then 1 else 0
) / cyclicmemory >= aperc
do lmin + mstep * dbx;
def ub = fold ubx = 0 to 100
while (fold ulx = 0 to cyclicmemory - 1
with a
do a + if GetValue(crsi, ulx) >= lmax - mstep * ubx then 1 else 0
) / cyclicmemory >= aperc
do lmax - mstep * ubx;
I honestly hope this is a simple mistake, I'll shoulder that shame no problem, I've just always wanted to get this indicator to be truly dynamic. You can see all the folds that go to "cyclicmemory -1" are where this error occurs, but they all seem fine to me. Naturally, if I hard code any integer to the cyclicmemory variable, the code works fine. Is there any possible workaround for this? It's literally the one thing stopping Cyclic RSI v2 from working.