QQE MTF (Multi Timeframe) for ThinkorSwim

Xiuying

New member
Had this on the backburner for quite awhile and finally got off my lazy ass to clean it up a bit.(Searched and didn't see anyone post one yet, so hopefully I didn't miss it)

QQE indicator with a MTF spin on it. It has two variations with "1" being the faster one(6/3 2.621 settings) and "2" being the slower one(20/5/ 4.236 settings).

Time frames go in order of Bottom to top with bottom being the current timeframe you're on and working it's way upward. Default secondary timeframes are 15m and 30m.

Colors:
Green = Fast > Slower
Red = Fast < Slower
White = Fast < Slower and in Oversold Territory(Below 30)
Blue = Fast > Slower and in Overbought Territory(Above 70)

The last two colors only apply to the bottom row(current time frame) considering that I mainly use this for day trading on the 5m and those OS & OB areas help me a lot. I am currently back testing to see how often the same areas will work on higher time frames. Currently 15m is the top contender for being great for the colors, so I'll be more than likely adding in code to detect that aggregation period to allow it on the 15m.

I would also like to thank @BenTen for posting the QQE thread months ago which got me to start using QQE in the first place and testing to see what could be done with it in general to improve it.

Code:
#QQEV2 7/18/2020
#MTF QQE based off of the first version I made, Ended up sticking with only MTF and getting rid of the extra "Fib variations" for this version.
#Timeframes will go from Bottom to Top with the bottom being the current time frame
#Green = Fast > Slow and Blue indicates that Fast > Slow AND it's in overbought territory while white will indicate fast < slow and in oversold Territory.
#This feature will only appear for the current time ONLY, as I mainly use it to daytrade on the 5m where it helps me avoid sudden drops
#Author - Xiuying

#Update 10/05/2020 - Replaced the inputs to change the Slow/Fast/QQE with a simple Variation input. Input "1" shall be the usual fast 6/3 and anything not "1" will be the generic 20/5
#Update 11/07/2020 - Ended up changing the original lines that I had and switched to something simple like the MMARB that I imported, however the lines would be too "Trippy" so changed to singular bubbles

#Future - I plan on adding anothing feature based off of the trend that is usually associated with QQE, Going to do some more backtesting before I do so.

# The Original Base that this all started from was the one that Kory Gill converted for Benten at useThinkScript.com



declare lower;

input Variation =  1;
Input Agg2 = {"1 min", "3 min", "5 min", "10 min", default  "15 min", "30 min", "60 min", "120 min", "Daily", "Weekly", "Monthly"};
Input Agg3 = { "3 min", "5 min", "10 min", "15 min", default  "30 min", "60 min", "120 min", "Daily","Weekly", "Monthly"};


###Agg Code
def middleAggregation;

switch (Agg2) {
case "1 min":
    middleAggregation = AggregationPeriod.MIN;
case "3 min":
    middleAggregation = AggregationPeriod.THREE_MIN;
case "5 min":
    middleAggregation = AggregationPeriod.FIVE_MIN;
case "10 min":
    middleAggregation = AggregationPeriod.TEN_MIN;
case "15 min":
    middleAggregation = AggregationPeriod.FIFTEEN_MIN;
case "30 min":
    middleAggregation = AggregationPeriod.THIRTY_MIN;
case "60 min":
    middleAggregation = AggregationPeriod.HOUR;
case "120 min":
    middleAggregation = AggregationPeriod.TWO_HOURS;
case "Daily":
    middleAggregation = AggregationPeriod.DAY;
case "Weekly":
    middleAggregation = AggregationPeriod.WEEK;
case "Monthly":
    middleAggregation = AggregationPeriod.MONTH;
}

def highestAggregation;
switch (Agg3) {
case "3 min":
    highestAggregation = AggregationPeriod.THREE_MIN;
case "5 min":
    highestAggregation = AggregationPeriod.FIVE_MIN;
case "10 min":
    highestAggregation = AggregationPeriod.TEN_MIN;
case "15 min":
    highestAggregation = AggregationPeriod.FIFTEEN_MIN;
case "30 min":
    highestAggregation = AggregationPeriod.THIRTY_MIN;
case "60 min":
    highestAggregation = AggregationPeriod.HOUR;
case "120 min":
    highestAggregation = AggregationPeriod.TWO_HOURS;
case "Daily":
    highestAggregation = AggregationPeriod.DAY;
case "Weekly":
    highestAggregation = AggregationPeriod.WEEK;
case "Monthly":
    highestAggregation = AggregationPeriod.MONTH;
}

####

def RSI_Period = if Variation != 1 then 20 else 6;
def Slow_Factor = if Variation != 1 then 5 else 3;
def QQE = if Variation != 1 then 4.236 else 2.621;

def Wilder_Period = RSI_Period * 2 - 1;
def vClose = close;
def vClose15 = close(period = middleAggregation);
def vClose30 = close(period = highestAggregation);

def rsi = RSI(price = vClose, length = RSI_Period).RSI;
def rsi_ma = MovingAverage(AverageType.EXPONENTIAL, rsi, Slow_Factor);
def atr_rsi = AbsValue(rsi_ma[1] - rsi_ma);
def atr_rsi_ma = MovingAverage(AverageType.EXPONENTIAL, atr_rsi, Wilder_Period);
def dar = MovingAverage(AverageType.EXPONENTIAL, atr_rsi_ma, Wilder_Period) * QQE;

def DeltaFastAtrRsi = dar;
def RSIndex = rsi_ma;
def newshortband =  RSIndex + DeltaFastAtrRsi;
def newlongband = RSIndex - DeltaFastAtrRsi;

def longband = if RSIndex[1] > longband[1] and RSIndex > longband[1]
               then Max(longband[1], newlongband)
               else newlongband;

def shortband = if RSIndex[1] < shortband[1] and  RSIndex < shortband[1]
                then Min(shortband[1], newshortband)
                else newshortband;

def trend = if Crosses(RSIndex, shortband[1])
            then 1
            else if Crosses(longband[1], RSIndex)
            then -1
            else if !IsNaN(trend[1])
            then trend[1]
            else 1;

def FastAtrRsiTL = if trend == 1
                   then longband
                   else shortband;

def pFastAtrRsiTL = FastAtrRsiTL;
def pRsiMa = rsi_ma;
def line50 = 50;

##################
def rsi15 = RSI(price = vClose15, length = RSI_Period).RSI;
def rsi_ma15 = MovingAverage(AverageType.EXPONENTIAL, rsi15, Slow_Factor);
def atr_rsi15 = AbsValue(rsi_ma15[1] - rsi_ma15);
def atr_rsi_ma15 = MovingAverage(AverageType.EXPONENTIAL, atr_rsi15, Wilder_Period);
def dar15 = MovingAverage(AverageType.EXPONENTIAL, atr_rsi_ma15, Wilder_Period) * QQE;

def DeltaFastAtrRsi15 = dar15;
def RSIndex15 = rsi_ma15;
def newshortband15 =  RSIndex15 + DeltaFastAtrRsi15;
def newlongband15 = RSIndex15 - DeltaFastAtrRsi15;

def longband15 = if RSIndex15[1] > longband15[1] and RSIndex15 > longband15[1]
               then Max(longband15[1], newlongband15)
               else newlongband15;

def shortband15 = if RSIndex15[1] < shortband15[1] and  RSIndex15 < shortband15[1]
                then Min(shortband15[1], newshortband15)
                else newshortband15;

def trend15 = if Crosses(RSIndex15, shortband15[1])
            then 1
            else if Crosses(longband15[1], RSIndex15)
            then -1
            else if !IsNaN(trend15[1])
            then trend15[1]
            else 1;

def FastAtrRsiTL15 = if trend15 == 1
                   then longband15
                   else shortband15;

def pFastAtrRsiTL15 = FastAtrRsiTL15;
def pRsiMa15 = rsi_ma15;
def OS = 30;
def OB = 70;




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

def rsi30 = RSI(price = vClose30, length = RSI_Period).RSI;
def rsi_ma30 = MovingAverage(AverageType.EXPONENTIAL, rsi30, Slow_Factor);
def atr_rsi30 = AbsValue(rsi_ma30[1] - rsi_ma30);
def atr_rsi_ma30 = MovingAverage(AverageType.EXPONENTIAL, atr_rsi30, Wilder_Period);
def dar30 = MovingAverage(AverageType.EXPONENTIAL, atr_rsi_ma30, Wilder_Period) * QQE;

def DeltaFastAtrRsi30 = dar30;
def RSIndex30 = rsi_ma30;
def newshortband30 =  RSIndex30 + DeltaFastAtrRsi30;
def newlongband30 = RSIndex30 - DeltaFastAtrRsi30;

def longband30 = if RSIndex30[1] > longband30[1] and RSIndex30 > longband30[1]
               then Max(longband30[1], newlongband30)
               else newlongband30;

def shortband30 = if RSIndex30[1] < shortband30[1] and  RSIndex30 < shortband30[1]
                then Min(shortband30[1], newshortband30)
                else newshortband30;

def trend30 = if Crosses(RSIndex30, shortband30[1])
            then 1
            else if Crosses(longband30[1], RSIndex30)
            then -1
            else if !IsNaN(trend30[1])
            then trend30[1]
            else 1;

def FastAtrRsiTL30 = if trend30 == 1
                   then longband30
                   else shortband30;

def pFastAtrRsiTL30 = FastAtrRsiTL30;
def pRsiMa30 = rsi_ma30;


##################
plot Five = 0;
plot Fifteen = 1;
plot Thirty = 2;


### Color Coding
Five.SetPaintingStrategy(paintingStrategy = PaintingStrategy.POINTS);
Five.AssignValueColor(if pfastAtrRsiTL < prsiMa and prsima > OB then color.blue else if pfastAtrRsiTL < prsiMa then color.green else if  prsima < OS then color.white else color.red);
Fifteen.SetPaintingStrategy(paintingStrategy = PaintingStrategy.POINTS);
Fifteen.AssignValueColor(if pfastAtrRsiTL15 < prsiMa15 then color.green else color.red);
Thirty.SetPaintingStrategy(paintingStrategy = PaintingStrategy.POINTS);
Thirty.AssignValueColor(if pfastAtrRsiTL30 < prsiMa30 then color.green else color.red);

Five.SetLineWeight(5);
Fifteen.SetLineWeight(5);
Thirty.SetLineWeight(5);

http://tos.mx/b0AAp9f

An Example from NVDA, We can see the higher Aggregation period is staying Green overall with a few dips on the lower 5m time frame I've been using.
I do plan on adding a "Flat" trend that QQE has to point out when a crossover could be occurring, but still figuring out a few more variables to that equation(I.E, Above or Below 50, How often they matter above 70 or below 30, etc etc)

QQEVExample.jpg
 

tem2005

Member
VIP
thanks looks great. the coloring of bubbles get changed during live trading?

can we have a label that indicates the result of the three bubbles?

sorry been too long!
 

Xiuying

New member
@tem2005 There is a chance of the bubbles getting changed live(only the current one, not past) , more often than not it's when there is a cross that is being attempted or from sudden Spikes/Drops. Like what happened with BYND today on the drop down of News.

I could look into adding a label to make it easier to understand.
 

Xiuying

New member
appreciated that so much

so the 5 min bubble itself represents the current candle forming?
It's default set for working on the 5m chart, since that's what I mostly use, but you can set it up for any timeframe you want. You can even change the agg periods to 10m and 15m, if that's what you prefer.

Just remember the bottom row will always be the current timeframe for the chart.
 

tem2005

Member
VIP
@Xiuying is there a chance for the 15 or 30min bubbles to change the last representative bubbles after closing of the candle?
For example, if 15 min cureent bubbles red and candled closed green somewhat big, so last 3 bubbles get changed to green?

I hope I explained it well!
 

Xiuying

New member
@Xiuying is there a chance for the 15 or 30min bubbles to change the last representative bubbles after closing of the candle?
For example, if 15 min cureent bubbles red and candled closed green somewhat big, so last 3 bubbles get changed to green?

I hope I explained it well!
You explained it well, don't worry.

My assumption would be that they do if they're apart of that 15m/30m interval. Going over the past data as well, for the 15m and 30m, you can always see that the start or end of their respected time frames.

Actually, I might just add in some form of grouping for the aggregated periods to make it easier to see when certain bars are starting/ending.

Hm, Another idea as well I could try.
 

tem2005

Member
VIP
yes, i asked because i saw the majority get changed right at the start of forming the candle which may indicate that after the candle closing it paints its meant bubbles..But then i saw some changed within the forming process. i think we need to test it using Demand.
 

Xiuying

New member
yes, i asked because i saw the majority get changed right at the start of forming the candle which may indicate that after the candle closing it paints its meant bubbles..But then i saw some changed within the forming process. i think we need to test it using Demand.
OnDemand has been buggy for me as of late, but I'll be sure to keep an eye on it as I trade throughout the day.
 

rad14733

Well-known member
VIP
OnDemand has been buggy for me as of late, but I'll be sure to keep an eye on it as I trade throughout the day.
I have tried it a couple times again in the past week and it's essentially worthless...!!! :mad: Locks up, lags, sporadic trade entries and exits...

During the day you're better off using Paper Trading...
 

Xiuying

New member
I have tried it a couple times again in the past week and it's essentially worthless...!!! :mad: Locks up, lags, sporadic trade entries and exits...

During the day you're better off using Paper Trading...
I'm glad It's not just me who is having issues with OnDemand. I messaged support about it, but they gave the generic "Not our fault" statement.
 

lostmarxbro

New member
Worked for me, only on the 15-minute time frame though. Would love to see a larger time frame for larger moves but still great work. Really helps enrty
 

Xiuying

New member
Is there any way that the time periods can be made to reflect smaller time periods like 1min, 2min, and 5 min?
Yea, you would just need to go into Studies and click the Cogwheel next to the indicator and change it to those periods. However, if you're current chart is on a higher time period, then the lower ones won't work.

However, I only have 1/3/5 as the smallest ones, don't have Two since I saw it as Redundant.
 

Similar threads

Top