Momentum Keltner Channels for ThinkorSwim

P

Pensar

Active member
VIP
I made this indicator some time ago based on the FW_MOBO code. After doing a few changes recently, I thought I might share it here. :) It is similar to Raghee Horner's GRaB indicator, but uses keltner channels instead of offset 34 EMAs. I feel it is best for showing trends in the market.

Code:
# MomentumKeltnerChannels
# Pensar
# 06/06/2020
# Based on the FW_MOBO code by TOS user davidinc (aka Firstwave, aka David Elliott)
# Modified code to use Keltner Channels, changed code structure.
# Added colored price and user-adjustable global colors.

#Inputs
input length       =     34;
input factor       =     0.5;
input displace     =     0;
input price        =     close;
input type         =     AverageType.SIMPLE;
input pricecolor   =     yes;
input fill         =     yes;
input arrows       =     yes;
input alerts       =     yes;
input sound        =     {default "Ding", "Bell", "Chimes", "NoSound", "Ring"};

#Variables
def nan      =   double.nan;
def shift    =   factor * MovingAverage(type, TrueRange(high, close, low), length);
def avg      =   MovingAverage(type, price, length);
def line1    =   avg[-displace] - shift[-displace];
def line2    =   avg[-displace] + shift[-displace];
def Chg      =   if(close > line2, 1, if(close < line1, -1, 0));
def Hold     =   CompoundValue(1,if(Hold[1] == Chg or Chg == 0, Hold[1], if(Chg == 1, 1, -1)), 0);
def ArUp     =   if !arrows or Hold[0] == Hold[1] then nan else if Hold[0] == 1 then line1 else nan;
def ArDn     =   if !arrows or Hold[0] == Hold[1] then nan else if Hold[0] == -1 then line2 else nan;
def LBUp     =   if fill and Hold[0] == 1 then line2 else nan;
def UBUp     =   if fill and Hold[0] == 1 then line1 else nan;
def LBDn     =   if fill and Hold[0] == -1 then line2 else nan;
def UBDn     =   if fill and Hold[0] == -1 then line1 else nan;
def AlertUp  =   alerts and Hold[1] ==  1 and (Hold[1] <> Hold[2]);
def AlertDn  =   alerts and Hold[1] == -1 and (Hold[1] <> Hold[2]);

#Colors
DefineGlobalColor("Cloud Up", color.dark_green);
DefineGlobalColor("Cloud Dn", color.dark_red);
DefineGlobalColor("Channel Up", color.green);
DefineGlobalColor("Channel Down", color.red);
DefineGlobalColor("Price Up", color.green);
DefineGlobalColor("Price Neutral", color.gray);
DefineGlobalColor("Price Down", color.red);

#Plots
plot UB = line1;
     UB.SetLineWeight(1);
     UB.AssignValueColor(if Hold[0] == 1 then GlobalColor("Channel Up")
                         else GlobalColor("Channel Down"));
plot LB = line2;
     LB.SetLineWeight(1);
     LB.AssignValueColor(if Hold[0] == 1 then GlobalColor("Channel Up")
                         else GlobalColor("Channel Down"));
plot BOA = ArUp;
     BOA.SetPaintingStrategy(PaintingStrategy.Arrow_Up);
     BOA.SetDefaultColor(color.green);
     BOA.SetLineWeight(2);
plot BDA = ArDn;
     BDA.SetPaintingStrategy(PaintingStrategy.Arrow_Down);
     BDA.SetDefaultColor(color.red);
     BDA.SetLineWeight(2);

#Clouds
AddCloud(LBUp, UBUp, GlobalColor("Cloud Up"), GlobalColor("Cloud Dn"));
AddCloud(LBDn, UBDn, GlobalColor("Cloud Dn"), GlobalColor("Cloud Up"));

#Price Color
AssignPriceColor(if pricecolor then if close > line2 then GlobalColor("Price Up")
                 else if close < line1 then GlobalColor("Price Down")
                 else GlobalColor("Price Neutral")
                 else color.current);

#Alerts
Alert(AlertUp, "BREAKOUT!",  Alert.Bar, Sound);
Alert(AlertDn, "BREAKDOWN!", Alert.Bar, Sound);

# --- End code ---
 
technicallydreaming

technicallydreaming

Member
Loving it! Very good results looking back in time on the charts. Not sure if arrows repaints during live trading yet however.
 
C

camerdr

New member
VIP
@Pensar, thanks for this indicator, it comes in handy. I have made a scanner out of it as seen below. Can you please help fine tune it so that it can have a lookback period of 1 or max 2 candles?

Code:
# MomentumKeltnerChannels
# Pensar
# 06/06/2020
# Based on the FW_MOBO code by TOS user davidinc (aka Firstwave, aka David Elliott)
# Modified code to use Keltner Channels, changed code structure.
# Added colored price and user-adjustable global colors.

#Inputs
input length       =     34;
input factor       =     0.5;
input displace     =     0;
input price        =     close;
input type         =     AverageType.SIMPLE;
input pricecolor   =     yes;
input fill         =     yes;
input arrows       =     yes;
input alerts       =     yes;


#Variables
def nan      =   double.nan;
def shift    =   factor * MovingAverage(type, TrueRange(high, close, low), length);
def avg      =   MovingAverage(type, price, length);
def line1    =   avg[-displace] - shift[-displace];
def line2    =   avg[-displace] + shift[-displace];
def Chg      =   if(close > line2, 1, if(close < line1, -1, 0));
def Hold     =   CompoundValue(1,if(Hold[1] == Chg or Chg == 0, Hold[1], if(Chg == 1, 1, -1)), 0);
def ArUp     =   if !arrows or Hold[0] == Hold[1] then nan else if Hold[0] == 1 then line1 else nan;
def ArDn     =   if !arrows or Hold[0] == Hold[1] then nan else if Hold[0] == -1 then line2 else nan;
def LBUp     =   if fill and Hold[0] == 1 then line2 else nan;
def UBUp     =   if fill and Hold[0] == 1 then line1 else nan;
def LBDn     =   if fill and Hold[0] == -1 then line2 else nan;
def UBDn     =   if fill and Hold[0] == -1 then line1 else nan;
def AlertUp  =   alerts and Hold[1] ==  1 and (Hold[1] <> Hold[2]);
def AlertDn  =   alerts and Hold[1] == -1 and (Hold[1] <> Hold[2]);

#plot Buy = AlertUp;
plot Sell = AlertDn;
 
P

Pensar

Active member
VIP
@camerdr Check if this provides the results you wish -

Scanner Code -
Code:
# Momentum Keltner Channels Scan
# Based on the FW_MOBO code by TOS user davidinc (aka Firstwave, aka David Elliott)

input length       =     34;
input factor       =     0.5;
input displace     =     0;
input price        =     close;
input type         =     AverageType.SIMPLE;

def nan      =   double.nan;
def shift    =   factor * MovingAverage(type, TrueRange(high, close, low), length);
def avg      =   MovingAverage(type, price, length);
def line1    =   avg[-displace] - shift[-displace];
def line2    =   avg[-displace] + shift[-displace];
def Chg      =   if(close > line2, 1, if(close < line1, -1, 0));
def Hold     =   CompoundValue(1,if(Hold[1] == Chg or Chg == 0, Hold[1], if(Chg == 1, 1, -1)), 0);

def n1 = Hold[0] == 1;
def n2 = Hold[0] == -1;
def countup = if n1 and !n1[1] then 1 else countup[1]+1;
def countdn = if n2 and !n2[1] then 1 else countdn[1]+1;

plot scan_for_break_up = if n1 then if(countup < 3, 1, 0) else 0;
#plot scan_for_break_down = if n2 then if(countdn < 3, 1, 0) else 0;

#End of code
Also, here is a watchlist column for anyone interested. Figured might as well make one. :)

Watchlist Code -
Code:
# Momentum Keltner Channels Watchlist Column
# Based on the FW_MOBO code by TOS user davidinc (aka Firstwave, aka David Elliott)
# The count displayed in the watchlist shows the number of bars since a break up or break down

input length       =     34;
input factor       =     0.5;
input displace     =     0;
input price        =     close;
input type         =     AverageType.SIMPLE;

def nan      =   double.nan;
def shift    =   factor * MovingAverage(type, TrueRange(high, close, low), length);
def avg      =   MovingAverage(type, price, length);
def line1    =   avg[-displace] - shift[-displace];
def line2    =   avg[-displace] + shift[-displace];
def Chg      =   if(close > line2, 1, if(close < line1, -1, 0));
def Hold     =   CompoundValue(1,if(Hold[1] == Chg or Chg == 0, Hold[1], if(Chg == 1, 1, -1)), 0);

def n1 = Hold[0] == 1;
def n2 = Hold[0] == -1;
def count1 = if n1 and !n1[1] then 1 else count1[1]+1;
def count2 = if n2 and !n2[1] then 1 else count2[1]+1;

plot n = if n1 then count1 else if n2 then count2 else double.nan;
     n.setdefaultcolor(color.black);
assignbackgroundcolor(if n1 and count1 then color.green else color.red);
#End of code
 
Last edited:
C

camerdr

New member
VIP
@Pensar , thank you so so much. It works like a charm especially the watchlist.
 
D

dinodotcom

Member
2019 Donor
@Pensar, regarding the values in the watch list, is there any significance to the numerical values displayed in the watch list column? Meaning that anything over a certain value would equate to a better trade etc? Higher numbers vs lower numbers equate to better trades?
 
P

Pensar

Active member
VIP
@dinodotcom The only significance of the numbers in the watchlist column is to count how many bars since a breakout/breakdown.

It can help in knowing which instruments have been running for a while vs those that are just breaking out/down.
 
M

mdtn

New member
VIP
Wow, it looks great. For the watchlist, can you please explain what the number mean, what does it represent?
Thanks Pensar!
 
P

PhinsUp

New member
VIP
@Pensar great indicator, looks great. Do you mind explaining what time frame is best used for this? Also how does one follow a trend based on this? As long as its above green channel, means trending upward correct? Thanks in advance!
 
J

JGilde

New member
VIP
@Pensar I'm very new to all this scripting and the settings for TOS. So I added the above script for the study and it displays correctly on the chart. I'm trying to add the scan script and watchlist scripts. What do I enter as the conditions? Like crosses, crosses above and more and within ? bars, etc? Are those values the same for both the scan and the watchlist's custom conditions? Thank you.
 
raghavag2004

raghavag2004

New member
2019 Donor
VIP
@camerdr @Pensar

Thanks alot for the great script, wrt to scanner & watch list having few Queries

Watch list custom column -> what settings to use like "true' or false" or value?
scanner - similar what exactly to use? if possible can you share it as export link for both?

After use Value i see the number of days in watch list column, hope its the right way i'm using correct me. Thanks in advance
 
Last edited:
P

Pensar

Active member
VIP
@JGilde @raghavag2004 The scan code, as currently written, finds breakouts or breakdowns less than three bars ago (depending on which side you are scanning for). The watchlist shows the count of the number of bars since a breakout or breakdown. No "crosses" or "crosses below" or "true/false settings" should be needed, just copy the code and paste into the TOS scan/watchlist code editor.
 
K

K_O_Trader

Member
This is a great indicator, especially when you use it with a relative volume column on you watchlist/scanner. I was using a supertrend for the longest time until I came across this, this is quicker and more reliable
 
K

K_O_Trader

Member
@Pensar Is there a way to make a label for this with anytime frame?
 
P

Pensar

Active member
VIP
@Pensar Is there a way to make a label for this with anytime frame?
@K_O_Trader Try out this label -

Code:
input length       =     34;
input factor       =     0.5;
input displace     =     0;
input agg          =     aggregationperiod.FIVE_MIN;
input type         =     AverageType.SIMPLE;
input label_text   =     "5m";

def h        =   high(period = agg);
def c        =   close(period = agg);
def l        =   low(period = agg);
def shift    =   factor * MovingAverage(type, TrueRange(h,c,l), length);
def avg      =   MovingAverage(type, c, length);
def line1    =   avg[-displace] - shift[-displace];
def line2    =   avg[-displace] + shift[-displace];
def Chg      =   if(c > line2, 1, if(c < line1, -1, 0));
def Hold     =   CompoundValue(1,if(Hold[1] == Chg or Chg == 0, Hold[1], if(Chg == 1, 1, -1)), 0);

def n1 = Hold[0] == 1;
def n2 = Hold[0] == -1;
def count1 = if n1 and !n1[1] then 1 else count1[1]+1;
def count2 = if n2 and !n2[1] then 1 else count2[1]+1;

AddLabel(1,label_text + " - " + if n1 then count1 else count2,
     if n1 then color.green
     else color.red);

#End of code
 
Last edited:
K

K_O_Trader

Member
@K_O_Trader Try out this label -

Code:
input length       =     34;
input factor       =     0.5;
input displace     =     0;
input agg          =     aggregationperiod.FIVE_MIN;
input type         =     AverageType.SIMPLE;
input label_text   =     "5m";

def h        =   high(period = agg);
def c        =   close(period = agg);
def l        =   low(period = agg);
def shift    =   factor * MovingAverage(type, TrueRange(h,c,l), length);
def avg      =   MovingAverage(type, c, length);
def line1    =   avg[-displace] - shift[-displace];
def line2    =   avg[-displace] + shift[-displace];
def Chg      =   if(c > line2, 1, if(c < line1, -1, 0));
def Hold     =   CompoundValue(1,if(Hold[1] == Chg or Chg == 0, Hold[1], if(Chg == 1, 1, -1)), 0);

AddLabel(1,label_text,
     if Hold == 1 then color.green
     else color.red);
That works great, is it possible to get the label with the number in it too?
 

Similar threads

Top