Offset Plotted Arrows For ThinkOrSwim

lucprokop

New member
So I was experimenting with EMA crosses and clouds and found a system that I think is good. It involves using the 3/8, 9/13, and 8/21 EMA cross. Each time there is a crosses of the EMAs the indicator plots an arrow (up arrow for fast>slow, down arrow for slow>fast). The problem that I am having is that sometimes the arrows from two separate crosses will plot directly over one another on the chart and I have to hover over a previous arrow of a certain cross to show which one triggered. Basically I have been looking everywhere to figured out how to offset where arrows will plot for a certain cross. For example, if the 8/13 cross and the 8/21 cross both happen on the same bar, the 8/21 cross will be offset just enough so that they don't plot directly on top of each other. I've attached photos and the script. What edits do I need to make to the script to fix this issue.

Here are two arrows plotting directly over each other on the same bar:
9/13 EMA Cross Arrow shown here
3/8 EMA Cross Arrow only shows when i hover mouse over it

Here is where I want to move the 9/13 cross arrow:

Here is the code:
Code:
input price = close;#hint price: The price used to calculate the crossover. <b>(Default is CLOSE)</b>
input fastLength = 8;#hint fastLength: The number of bars used to calculate the fast moving average. <b>(Default is 3)</b>
input slowLength = 21;#hint slowLength: The number of bars used to calculate the slow moving average. <b>(Default is 8)</b>
input slowAvgType = {default Simple, Exponential, Weighted, Wilders, Hull};#hint slowAvgType: Type of the fast moving average to be used for calculation. <b>(Default is Expontential)</b>
input fastAvgType = {default Simple, Exponential, Weighted, Wilders, Hull};#hint fastAvgType: Type of the fast moving average to be used for calculation. <b>(Default is Exponential)</b>
Input DoArrows = no;#hint DoArrows:Yes shows arrows to define crosses
Input DoPlots = yes;#hint DoPlots: Yes shows MA plots to define crosses. Default is 'YES'
Input DoAlerts = No;#hint DoAlerts:No turns off alerts
Assert( fastLength < slowLength, "fastLength ["+fastLength+"] must be less than slowLength["+slowLength+"]");

def fastAvg;
switch (slowAvgType) {
case Simple:
    fastAvg = Average(price, fastLength);
case Exponential:
    fastAvg = ExpAverage(price, fastLength);
case Weighted:
    fastAvg = wma(price, fastLength);
case Wilders:
    fastAvg = WildersAverage(price, fastLength);
case Hull:
    fastAvg = HullMovingAvg(price, fastLength);
}

def slowAvg;
switch (fastAvgType) {
case Simple:
    slowAvg = Average(price, slowLength);
case Exponential:
    slowAvg = ExpAverage(price, slowLength);
case Weighted:
    slowAvg = wma(price, slowLength);
case Wilders:
    slowAvg = WildersAverage(price, slowLength);
case Hull:
    slowAvg = HullMovingAvg(price, slowLength);
}

plot signalXup = If DoArrows Then crosses(fastAvg, slowAvg, CrossingDirection.above) else Double.nan;
signalXup.SetDefaultColor(Color.pink);
signalXup.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_UP);
signalXup.SetLineWeight(3);

plot signalXdn =  If DoArrows Then crosses(fastAvg, slowAvg, CrossingDirection.below) else Double.nan;
signalXdn.SetDefaultColor(Color.Green);
signalXdn.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_DOWN);
signalXdn.SetLineWeight(3);
 
I tried to do non-boolean arrows to fix the problem but it just results in arrows being plotted at the bottom of my chart and for every bar

All I changed was:

signalXup.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_UP);

and

signalXdn.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_DOWN);

to

signalXup.SetPaintingStrategy(PaintingStrategy.ARROW_UP);
signalXdn.SetPaintingStrategy(PaintingStrategy.ARROW_DOWN);

 
@lucprokop When switching from boolean to non-boolean arrows, you have to assign where you want the arrow to plot. Here's an example code. I also coded an example offset for the arrow so that it doesn't stack the arrows.
The "!up[1] and up" simply means that the moving averages (defined in the "def up") are not crossed on the previous bar but are crossed on the current bar. That works the same as using "crosses" or "crosses above", etc. Just a different way to do it.

This is sample code and was coded here in the forum - I have no idea if it has errors or even how it looks, but its an example of how I might do it.
Code:
def up = fastavg > slowavg;
plot signalXup = If DoArrows and !up[1] and up then low - (5 * ticksize()) else double.nan; # tells the arrow to plot at the low and subtracts an offset
signalXup.SetDefaultColor(Color.pink);
signalXup.SetPaintingStrategy(PaintingStrategy.ARROW_UP);
signalXup.SetLineWeight(3);
 
So I was experimenting with EMA crosses and clouds and found a system that I think is good. It involves using the 3/8, 9/13, and 8/21 EMA cross. Each time there is a crosses of the EMAs the indicator plots an arrow (up arrow for fast>slow, down arrow for slow>fast). The problem that I am having is that sometimes the arrows from two separate crosses will plot directly over one another on the chart and I have to hover over a previous arrow of a certain cross to show which one triggered. Basically I have been looking everywhere to figured out how to offset where arrows will plot for a certain cross. For example, if the 8/13 cross and the 8/21 cross both happen on the same bar, the 8/21 cross will be offset just enough so that they don't plot directly on top of each other. I've attached photos and the script. What edits do I need to make to the script to fix this issue.

Here are two arrows plotting directly over each other on the same bar:
9/13 EMA Cross Arrow shown here
3/8 EMA Cross Arrow only shows when i hover mouse over it

Here is where I want to move the 9/13 cross arrow:

Here is the code:
Code:
input price = close;#hint price: The price used to calculate the crossover. <b>(Default is CLOSE)</b>
input fastLength = 8;#hint fastLength: The number of bars used to calculate the fast moving average. <b>(Default is 3)</b>
input slowLength = 21;#hint slowLength: The number of bars used to calculate the slow moving average. <b>(Default is 8)</b>
input slowAvgType = {default Simple, Exponential, Weighted, Wilders, Hull};#hint slowAvgType: Type of the fast moving average to be used for calculation. <b>(Default is Expontential)</b>
input fastAvgType = {default Simple, Exponential, Weighted, Wilders, Hull};#hint fastAvgType: Type of the fast moving average to be used for calculation. <b>(Default is Exponential)</b>
Input DoArrows = no;#hint DoArrows:Yes shows arrows to define crosses
Input DoPlots = yes;#hint DoPlots: Yes shows MA plots to define crosses. Default is 'YES'
Input DoAlerts = No;#hint DoAlerts:No turns off alerts
Assert( fastLength < slowLength, "fastLength ["+fastLength+"] must be less than slowLength["+slowLength+"]");

def fastAvg;
switch (slowAvgType) {
case Simple:
    fastAvg = Average(price, fastLength);
case Exponential:
    fastAvg = ExpAverage(price, fastLength);
case Weighted:
    fastAvg = wma(price, fastLength);
case Wilders:
    fastAvg = WildersAverage(price, fastLength);
case Hull:
    fastAvg = HullMovingAvg(price, fastLength);
}

def slowAvg;
switch (fastAvgType) {
case Simple:
    slowAvg = Average(price, slowLength);
case Exponential:
    slowAvg = ExpAverage(price, slowLength);
case Weighted:
    slowAvg = wma(price, slowLength);
case Wilders:
    slowAvg = WildersAverage(price, slowLength);
case Hull:
    slowAvg = HullMovingAvg(price, slowLength);
}

plot signalXup = If DoArrows Then crosses(fastAvg, slowAvg, CrossingDirection.above) else Double.nan;
signalXup.SetDefaultColor(Color.pink);
signalXup.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_UP);
signalXup.SetLineWeight(3);

plot signalXdn =  If DoArrows Then crosses(fastAvg, slowAvg, CrossingDirection.below) else Double.nan;
signalXdn.SetDefaultColor(Color.Green);
signalXdn.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_DOWN);
signalXdn.SetLineWeight(3);

i had an idea for awhile for something like this, so here is my version
thanks @Pensar for mentioning ticksize. i forget to use that, and usually use a tiny number for a vertical offset.

---------------------------------

stacked arrows on crossings of average lines

look for crossings of 3 EMA pairs, 3/8, 9/13, 8/21

draw an arrow, when a pair of average lines cross.
up arrow for fast > slow , down arrow for slow > fast

if more than 1 crossings occur on the same bar, in the same direction, it draws stacked arrows.
if lower number(1 and/or 2) arrow(s) are not triggered, the higher number(2 and/or 3) arrows will shift vertically, to be closer to the candle.

the second average line in each pair is dashed

user inputs:
parameters for 6 averages: length & type. ( defaults are EXPONENTIAL)
color of average lines (per pair) and corresponding crossing arrow (0 - 9)
show_average_lines
show_crossing_arrows
show_description_labels
the size of arrows (1 to 5)
arrow_vertical_factor

length 8 is used twice, so only 5 lines are viewable

Ruby:
# stack_arrows_01

def price = close;
def na = double.nan;

input show_average_lines = yes;
input show_crossing_arrows = yes;
input show_description_labels = yes;

# ----------------------------------
input avg1_color = 6;
# 6 = green

#hint avg1_color:  10 colors used with getcolor(). \n  0 = magenta, 1 = cyan, 2 = pink, 3 = gray, 4 = org \n  5 = red, 6 = green, 7 = dark gray, 8 = yellow, 9 = white \n    .setDefaultColor( GetColor(1) );

input avg1a_len = 3;
input avg1a_type =  AverageType.EXPONENTIAL;
def ma1a = MovingAverage(avg1a_type, price, avg1a_len);

input avg1b_len = 8;
input avg1b_type =  AverageType.EXPONENTIAL;
def ma1b = MovingAverage(avg1b_type, price, avg1b_len);

plot pma1a = if show_average_lines then ma1a else na;
#pma1a.SetDefaultColor(Color.Green);
pma1a.SetDefaultColor(getcolor(avg1_color));
#pma1a.SetLineWeight(1);

plot pma1b = if show_average_lines then ma1b else na;
#pma1b.SetDefaultColor(Color.Green);
pma1b.SetDefaultColor(getcolor(avg1_color));
pma1b.SetStyle(Curve.MEDIUM_DASH);
#pma1b.SetLineWeight(1);

# ----------------------------------
input avg2_color = 0;

input avg2a_len = 9;
input avg2a_type =  AverageType.EXPONENTIAL;
def ma2a = MovingAverage(avg2a_type, price, avg2a_len);

input avg2b_len = 13;
input avg2b_type =  AverageType.EXPONENTIAL;
def ma2b = MovingAverage(avg2b_type, price, avg2b_len);

plot pma2a = if show_average_lines then ma2a else na;
pma2a.SetDefaultColor(getcolor(avg2_color));
#pma2a.SetLineWeight(1);

plot pma2b = if show_average_lines then ma2b else na;
pma2b.SetDefaultColor(getcolor(avg2_color));
pma2b.SetStyle(Curve.MEDIUM_DASH);
#pma2b.SetLineWeight(1);

# ----------------------------------
input avg3_color = 8;

input avg3a_len = 8;
input avg3a_type =  AverageType.EXPONENTIAL;
def ma3a = MovingAverage(avg3a_type, price, avg3a_len);

input avg3b_len = 21;
input avg3b_type =  AverageType.EXPONENTIAL;
def ma3b = MovingAverage(avg3b_type, price, avg3b_len);

plot pma3a = if show_average_lines then ma3a else na;
pma3a.SetDefaultColor(getcolor(avg3_color));
#pma3a.SetLineWeight(1);

plot pma3b = if show_average_lines then ma3b else na;
pma3b.SetDefaultColor(getcolor(avg3_color));
pma3b.SetStyle(Curve.MEDIUM_DASH);
#pma3b.SetLineWeight(1);

# --------------------------------------
# check if an avg pair has crossed
def x1u = (ma1a crosses above ma1b);
def x1d = (ma1a crosses below ma1b);
def x2u = (ma2a crosses above ma2b);
def x2d = (ma2a crosses below ma2b);
def x3u = (ma3a crosses above ma3b);
def x3d = (ma3a crosses below ma3b);
# ------------------------------------ 

input arrow_size = 3;
input arrow_vertical_factor = 10;
def vert = (ticksize() * arrow_vertical_factor * arrow_size);

# avg1 arrow is closest to bar , avg3 arrow is farthest from bar
# ------------------------------------

def adj = 0;
# calc vertical placement for arrows
def arrow3dwn = if !x3d then na else high + (vert * ((x1d + x2d + x3d) - adj));
def arrow2dwn = if !x2d then na else high + (vert * ((x1d + x2d) - adj));
def arrow1dwn = if !x1d then na else high + (vert * ((x1d) - adj));

def arrow1up = if !x1u then na else low - (vert * ((x1u) - adj));
def arrow2up = if !x2u then na else low - (vert * ((x1u + x2u) - adj));
def arrow3up = if !x3u then na else low - (vert * ((x1u + x2u + x3u) - adj));


# plot arrows for crossings, stacked if more than 1
plot pma3xdwn = if show_crossing_arrows then arrow3dwn else na;
plot pma2xdwn = if show_crossing_arrows then arrow2dwn else na;
plot pma1xdwn = if show_crossing_arrows then arrow1dwn else na;
plot pma1xup = if show_crossing_arrows then arrow1up else na;
plot pma2xup = if show_crossing_arrows then arrow2up else na;
plot pma3xup = if show_crossing_arrows then arrow3up else na;

pma3xdwn.SetPaintingStrategy(PaintingStrategy.ARROW_DOWN);
pma2xdwn.SetPaintingStrategy(PaintingStrategy.ARROW_DOWN);
pma1xdwn.SetPaintingStrategy(PaintingStrategy.ARROW_DOWN);
pma1xup.SetPaintingStrategy(PaintingStrategy.ARROW_up);
pma2xup.SetPaintingStrategy(PaintingStrategy.ARROW_up);
pma3xup.SetPaintingStrategy(PaintingStrategy.ARROW_up);

pma3xdwn.SetDefaultColor(getcolor(avg3_color));
pma2xdwn.SetDefaultColor(getcolor(avg2_color));
pma1xdwn.SetDefaultColor(getcolor(avg1_color));
pma1xup.SetDefaultColor(getcolor(avg1_color));
pma2xup.SetDefaultColor(getcolor(avg2_color));
pma3xup.SetDefaultColor(getcolor(avg3_color));

pma3xdwn.hidebubble();
pma2xdwn.hidebubble();
pma1xdwn.hidebubble();
pma1xup.hidebubble();
pma2xup.hidebubble();
pma3xup.hidebubble();

pma3xdwn.setlineweight(arrow_size);
pma2xdwn.setlineweight(arrow_size);
pma1xdwn.setlineweight(arrow_size);
pma1xup.setlineweight(arrow_size);
pma2xup.setlineweight(arrow_size);
pma3xup.setlineweight(arrow_size);

# ----------------------------------------
addlabel(show_description_labels, "avg1  " + avg1a_len + "/" + avg1b_len, getcolor(avg1_color));
addlabel(show_description_labels, "avg2  " + avg2a_len + "/" + avg2b_len, getcolor(avg2_color));
addlabel(show_description_labels, "avg3  " + avg3a_len + "/" + avg3b_len, getcolor(avg3_color));

# -------------------------------------------

input test_ticksize_label = no;
addlabel( test_ticksize_label , " ticksize " + ticksize(), color.cyan);
# -----------------------------------------

# https://tlc.thinkorswim.com/center/reference/thinkScript/Constants/AverageType
#  EXPONENTIAL
#  HULL
#  SIMPLE
#  WEIGHTED
#  WILDERS

# https://tlc.thinkorswim.com/center/reference/thinkScript/functions/look---feel/getcolor
# getcolors
#

CVS 30D 15min
6Wq19Ba.jpg


color numbers for getcolor()
https://tlc.thinkorswim.com/center/reference/thinkScript/Functions/Look---Feel/GetColor
 
i had an idea for awhile for something like this, so here is my version
thanks @Pensar for mentioning ticksize. i forget to use that, and usually use a tiny number for a vertical offset.

---------------------------------

stacked arrows on crossings of average lines

look for crossings of 3 EMA pairs, 3/8, 9/13, 8/21

draw an arrow, when a pair of average lines cross.
up arrow for fast > slow , down arrow for slow > fast

if more than 1 crossings occur on the same bar, in the same direction, it draws stacked arrows.
if lower number(1 and/or 2) arrow(s) are not triggered, the higher number(2 and/or 3) arrows will shift vertically, to be closer to the candle.

the second average line in each pair is dashed

user inputs:
parameters for 6 averages: length & type. ( defaults are EXPONENTIAL)
color of average lines (per pair) and corresponding crossing arrow (0 - 9)
show_average_lines
show_crossing_arrows
show_description_labels
the size of arrows (1 to 5)
arrow_vertical_factor

length 8 is used twice, so only 5 lines are viewable

Ruby:
# stack_arrows_01

def price = close;
def na = double.nan;

input show_average_lines = yes;
input show_crossing_arrows = yes;
input show_description_labels = yes;

# ----------------------------------
input avg1_color = 6;
# 6 = green

#hint avg1_color:  10 colors used with getcolor(). \n  0 = magenta, 1 = cyan, 2 = pink, 3 = gray, 4 = org \n  5 = red, 6 = green, 7 = dark gray, 8 = yellow, 9 = white \n    .setDefaultColor( GetColor(1) );

input avg1a_len = 3;
input avg1a_type =  AverageType.EXPONENTIAL;
def ma1a = MovingAverage(avg1a_type, price, avg1a_len);

input avg1b_len = 8;
input avg1b_type =  AverageType.EXPONENTIAL;
def ma1b = MovingAverage(avg1b_type, price, avg1b_len);

plot pma1a = if show_average_lines then ma1a else na;
#pma1a.SetDefaultColor(Color.Green);
pma1a.SetDefaultColor(getcolor(avg1_color));
#pma1a.SetLineWeight(1);

plot pma1b = if show_average_lines then ma1b else na;
#pma1b.SetDefaultColor(Color.Green);
pma1b.SetDefaultColor(getcolor(avg1_color));
pma1b.SetStyle(Curve.MEDIUM_DASH);
#pma1b.SetLineWeight(1);

# ----------------------------------
input avg2_color = 0;

input avg2a_len = 9;
input avg2a_type =  AverageType.EXPONENTIAL;
def ma2a = MovingAverage(avg2a_type, price, avg2a_len);

input avg2b_len = 13;
input avg2b_type =  AverageType.EXPONENTIAL;
def ma2b = MovingAverage(avg2b_type, price, avg2b_len);

plot pma2a = if show_average_lines then ma2a else na;
pma2a.SetDefaultColor(getcolor(avg2_color));
#pma2a.SetLineWeight(1);

plot pma2b = if show_average_lines then ma2b else na;
pma2b.SetDefaultColor(getcolor(avg2_color));
pma2b.SetStyle(Curve.MEDIUM_DASH);
#pma2b.SetLineWeight(1);

# ----------------------------------
input avg3_color = 8;

input avg3a_len = 8;
input avg3a_type =  AverageType.EXPONENTIAL;
def ma3a = MovingAverage(avg3a_type, price, avg3a_len);

input avg3b_len = 21;
input avg3b_type =  AverageType.EXPONENTIAL;
def ma3b = MovingAverage(avg3b_type, price, avg3b_len);

plot pma3a = if show_average_lines then ma3a else na;
pma3a.SetDefaultColor(getcolor(avg3_color));
#pma3a.SetLineWeight(1);

plot pma3b = if show_average_lines then ma3b else na;
pma3b.SetDefaultColor(getcolor(avg3_color));
pma3b.SetStyle(Curve.MEDIUM_DASH);
#pma3b.SetLineWeight(1);

# --------------------------------------
# check if an avg pair has crossed
def x1u = (ma1a crosses above ma1b);
def x1d = (ma1a crosses below ma1b);
def x2u = (ma2a crosses above ma2b);
def x2d = (ma2a crosses below ma2b);
def x3u = (ma3a crosses above ma3b);
def x3d = (ma3a crosses below ma3b);
# ------------------------------------

input arrow_size = 3;
input arrow_vertical_factor = 10;
def vert = (ticksize() * arrow_vertical_factor * arrow_size);

# avg1 arrow is closest to bar , avg3 arrow is farthest from bar
# ------------------------------------

def adj = 0;
# calc vertical placement for arrows
def arrow3dwn = if !x3d then na else high + (vert * ((x1d + x2d + x3d) - adj));
def arrow2dwn = if !x2d then na else high + (vert * ((x1d + x2d) - adj));
def arrow1dwn = if !x1d then na else high + (vert * ((x1d) - adj));

def arrow1up = if !x1u then na else low - (vert * ((x1u) - adj));
def arrow2up = if !x2u then na else low - (vert * ((x1u + x2u) - adj));
def arrow3up = if !x3u then na else low - (vert * ((x1u + x2u + x3u) - adj));


# plot arrows for crossings, stacked if more than 1
plot pma3xdwn = if show_crossing_arrows then arrow3dwn else na;
plot pma2xdwn = if show_crossing_arrows then arrow2dwn else na;
plot pma1xdwn = if show_crossing_arrows then arrow1dwn else na;
plot pma1xup = if show_crossing_arrows then arrow1up else na;
plot pma2xup = if show_crossing_arrows then arrow2up else na;
plot pma3xup = if show_crossing_arrows then arrow3up else na;

pma3xdwn.SetPaintingStrategy(PaintingStrategy.ARROW_DOWN);
pma2xdwn.SetPaintingStrategy(PaintingStrategy.ARROW_DOWN);
pma1xdwn.SetPaintingStrategy(PaintingStrategy.ARROW_DOWN);
pma1xup.SetPaintingStrategy(PaintingStrategy.ARROW_up);
pma2xup.SetPaintingStrategy(PaintingStrategy.ARROW_up);
pma3xup.SetPaintingStrategy(PaintingStrategy.ARROW_up);

pma3xdwn.SetDefaultColor(getcolor(avg3_color));
pma2xdwn.SetDefaultColor(getcolor(avg2_color));
pma1xdwn.SetDefaultColor(getcolor(avg1_color));
pma1xup.SetDefaultColor(getcolor(avg1_color));
pma2xup.SetDefaultColor(getcolor(avg2_color));
pma3xup.SetDefaultColor(getcolor(avg3_color));

pma3xdwn.hidebubble();
pma2xdwn.hidebubble();
pma1xdwn.hidebubble();
pma1xup.hidebubble();
pma2xup.hidebubble();
pma3xup.hidebubble();

pma3xdwn.setlineweight(arrow_size);
pma2xdwn.setlineweight(arrow_size);
pma1xdwn.setlineweight(arrow_size);
pma1xup.setlineweight(arrow_size);
pma2xup.setlineweight(arrow_size);
pma3xup.setlineweight(arrow_size);

# ----------------------------------------
addlabel(show_description_labels, "avg1  " + avg1a_len + "/" + avg1b_len, getcolor(avg1_color));
addlabel(show_description_labels, "avg2  " + avg2a_len + "/" + avg2b_len, getcolor(avg2_color));
addlabel(show_description_labels, "avg3  " + avg3a_len + "/" + avg3b_len, getcolor(avg3_color));

# -------------------------------------------

input test_ticksize_label = no;
addlabel( test_ticksize_label , " ticksize " + ticksize(), color.cyan);
# -----------------------------------------

# https://tlc.thinkorswim.com/center/reference/thinkScript/Constants/AverageType
#  EXPONENTIAL
#  HULL
#  SIMPLE
#  WEIGHTED
#  WILDERS

# https://tlc.thinkorswim.com/center/reference/thinkScript/functions/look---feel/getcolor
# getcolors
#

CVS 30D 15min
6Wq19Ba.jpg


color numbers for getcolor()
https://tlc.thinkorswim.com/center/reference/thinkScript/Functions/Look---Feel/GetColor

LEGEND!!

overlaid the arrows onto my EMA clouds, and disabled the EMA lines from your code...nice result


Having only the 8/21 EMA crossover cloud show removes a lot of clutter from the screen, while still having the arrows as labels for all three crossover sets lets be have multiple confirmations
 
i had an idea for awhile for something like this, so here is my version
thanks @Pensar for mentioning ticksize. i forget to use that, and usually use a tiny number for a vertical offset.

---------------------------------

stacked arrows on crossings of average lines

look for crossings of 3 EMA pairs, 3/8, 9/13, 8/21

draw an arrow, when a pair of average lines cross.
up arrow for fast > slow , down arrow for slow > fast

if more than 1 crossings occur on the same bar, in the same direction, it draws stacked arrows.
if lower number(1 and/or 2) arrow(s) are not triggered, the higher number(2 and/or 3) arrows will shift vertically, to be closer to the candle.

the second average line in each pair is dashed

user inputs:
parameters for 6 averages: length & type. ( defaults are EXPONENTIAL)
color of average lines (per pair) and corresponding crossing arrow (0 - 9)
show_average_lines
show_crossing_arrows
show_description_labels
the size of arrows (1 to 5)
arrow_vertical_factor

length 8 is used twice, so only 5 lines are viewable

Ruby:
# stack_arrows_01

def price = close;
def na = double.nan;

input show_average_lines = yes;
input show_crossing_arrows = yes;
input show_description_labels = yes;

# ----------------------------------
input avg1_color = 6;
# 6 = green

#hint avg1_color:  10 colors used with getcolor(). \n  0 = magenta, 1 = cyan, 2 = pink, 3 = gray, 4 = org \n  5 = red, 6 = green, 7 = dark gray, 8 = yellow, 9 = white \n    .setDefaultColor( GetColor(1) );

input avg1a_len = 3;
input avg1a_type =  AverageType.EXPONENTIAL;
def ma1a = MovingAverage(avg1a_type, price, avg1a_len);

input avg1b_len = 8;
input avg1b_type =  AverageType.EXPONENTIAL;
def ma1b = MovingAverage(avg1b_type, price, avg1b_len);

plot pma1a = if show_average_lines then ma1a else na;
#pma1a.SetDefaultColor(Color.Green);
pma1a.SetDefaultColor(getcolor(avg1_color));
#pma1a.SetLineWeight(1);

plot pma1b = if show_average_lines then ma1b else na;
#pma1b.SetDefaultColor(Color.Green);
pma1b.SetDefaultColor(getcolor(avg1_color));
pma1b.SetStyle(Curve.MEDIUM_DASH);
#pma1b.SetLineWeight(1);

# ----------------------------------
input avg2_color = 0;

input avg2a_len = 9;
input avg2a_type =  AverageType.EXPONENTIAL;
def ma2a = MovingAverage(avg2a_type, price, avg2a_len);

input avg2b_len = 13;
input avg2b_type =  AverageType.EXPONENTIAL;
def ma2b = MovingAverage(avg2b_type, price, avg2b_len);

plot pma2a = if show_average_lines then ma2a else na;
pma2a.SetDefaultColor(getcolor(avg2_color));
#pma2a.SetLineWeight(1);

plot pma2b = if show_average_lines then ma2b else na;
pma2b.SetDefaultColor(getcolor(avg2_color));
pma2b.SetStyle(Curve.MEDIUM_DASH);
#pma2b.SetLineWeight(1);

# ----------------------------------
input avg3_color = 8;

input avg3a_len = 8;
input avg3a_type =  AverageType.EXPONENTIAL;
def ma3a = MovingAverage(avg3a_type, price, avg3a_len);

input avg3b_len = 21;
input avg3b_type =  AverageType.EXPONENTIAL;
def ma3b = MovingAverage(avg3b_type, price, avg3b_len);

plot pma3a = if show_average_lines then ma3a else na;
pma3a.SetDefaultColor(getcolor(avg3_color));
#pma3a.SetLineWeight(1);

plot pma3b = if show_average_lines then ma3b else na;
pma3b.SetDefaultColor(getcolor(avg3_color));
pma3b.SetStyle(Curve.MEDIUM_DASH);
#pma3b.SetLineWeight(1);

# --------------------------------------
# check if an avg pair has crossed
def x1u = (ma1a crosses above ma1b);
def x1d = (ma1a crosses below ma1b);
def x2u = (ma2a crosses above ma2b);
def x2d = (ma2a crosses below ma2b);
def x3u = (ma3a crosses above ma3b);
def x3d = (ma3a crosses below ma3b);
# ------------------------------------

input arrow_size = 3;
input arrow_vertical_factor = 10;
def vert = (ticksize() * arrow_vertical_factor * arrow_size);

# avg1 arrow is closest to bar , avg3 arrow is farthest from bar
# ------------------------------------

def adj = 0;
# calc vertical placement for arrows
def arrow3dwn = if !x3d then na else high + (vert * ((x1d + x2d + x3d) - adj));
def arrow2dwn = if !x2d then na else high + (vert * ((x1d + x2d) - adj));
def arrow1dwn = if !x1d then na else high + (vert * ((x1d) - adj));

def arrow1up = if !x1u then na else low - (vert * ((x1u) - adj));
def arrow2up = if !x2u then na else low - (vert * ((x1u + x2u) - adj));
def arrow3up = if !x3u then na else low - (vert * ((x1u + x2u + x3u) - adj));


# plot arrows for crossings, stacked if more than 1
plot pma3xdwn = if show_crossing_arrows then arrow3dwn else na;
plot pma2xdwn = if show_crossing_arrows then arrow2dwn else na;
plot pma1xdwn = if show_crossing_arrows then arrow1dwn else na;
plot pma1xup = if show_crossing_arrows then arrow1up else na;
plot pma2xup = if show_crossing_arrows then arrow2up else na;
plot pma3xup = if show_crossing_arrows then arrow3up else na;

pma3xdwn.SetPaintingStrategy(PaintingStrategy.ARROW_DOWN);
pma2xdwn.SetPaintingStrategy(PaintingStrategy.ARROW_DOWN);
pma1xdwn.SetPaintingStrategy(PaintingStrategy.ARROW_DOWN);
pma1xup.SetPaintingStrategy(PaintingStrategy.ARROW_up);
pma2xup.SetPaintingStrategy(PaintingStrategy.ARROW_up);
pma3xup.SetPaintingStrategy(PaintingStrategy.ARROW_up);

pma3xdwn.SetDefaultColor(getcolor(avg3_color));
pma2xdwn.SetDefaultColor(getcolor(avg2_color));
pma1xdwn.SetDefaultColor(getcolor(avg1_color));
pma1xup.SetDefaultColor(getcolor(avg1_color));
pma2xup.SetDefaultColor(getcolor(avg2_color));
pma3xup.SetDefaultColor(getcolor(avg3_color));

pma3xdwn.hidebubble();
pma2xdwn.hidebubble();
pma1xdwn.hidebubble();
pma1xup.hidebubble();
pma2xup.hidebubble();
pma3xup.hidebubble();

pma3xdwn.setlineweight(arrow_size);
pma2xdwn.setlineweight(arrow_size);
pma1xdwn.setlineweight(arrow_size);
pma1xup.setlineweight(arrow_size);
pma2xup.setlineweight(arrow_size);
pma3xup.setlineweight(arrow_size);

# ----------------------------------------
addlabel(show_description_labels, "avg1  " + avg1a_len + "/" + avg1b_len, getcolor(avg1_color));
addlabel(show_description_labels, "avg2  " + avg2a_len + "/" + avg2b_len, getcolor(avg2_color));
addlabel(show_description_labels, "avg3  " + avg3a_len + "/" + avg3b_len, getcolor(avg3_color));

# -------------------------------------------

input test_ticksize_label = no;
addlabel( test_ticksize_label , " ticksize " + ticksize(), color.cyan);
# -----------------------------------------

# https://tlc.thinkorswim.com/center/reference/thinkScript/Constants/AverageType
#  EXPONENTIAL
#  HULL
#  SIMPLE
#  WEIGHTED
#  WILDERS

# https://tlc.thinkorswim.com/center/reference/thinkScript/functions/look---feel/getcolor
# getcolors
#

CVS 30D 15min
6Wq19Ba.jpg


color numbers for getcolor()
https://tlc.thinkorswim.com/center/reference/thinkScript/Functions/Look---Feel/GetColor

Having a slight problem on further testing:

For different tickers then offset size needs to be different or arrows will / will not overlap, sometimes the space between arrows becomes huge

$MAPS, vertical factor set to 1, plenty of space between arrows

$TSLA, vertical factor also 1, arrows are overlapping each other


I also noticed that the vertical factor applies to all arrows, that being: when you make the vertical factor 50 its offsets all arrows by 50 so that even the bars with only one arrow have a huge offset. looks weird

it seems that the vertical size applies to all arrows, and grows exponentially the larger you make the number

is there a way to make is so that the vertical factor will only offset ONE arrow if it is overlaid on top of a bar that already has 1
 
Ok, so I'm not good with thinkscript and legit have never learned how to code with it this is just what I've observed through changing variables / values. The arrows are non-boolean and are thus basing their vertical offset on the price of that ticker that you are charting. This means that for the $AAPL ($179) chart, the arrows are plotting based on a much higher price than say if the arrows were plotting on a chart of $MAPS ($6.00). This means that the vertical offset of the arrows will always have to be changed when you switch between stocks that have a drastically different price.

This problem could be solved simply by making is so that the arrows always plot at a certain distance from the BAR, not necessarily the price of the bar. So...standardizing the unit of measurement across all charts of a stocks, not based on price, but based on visual size of the bar. Also to make it simpler, you can have it so that the longest EMA crossover arrow will always plot a certain distance (the furthest) from the bar, even if it is the only arrow on that bar. Essentially the arrow of a specific crossover will always plot at a certain visual distance from the bar it is on (ie. the shortest EMA crossover always plots near the bar, the middle EMA arrow always plots about 1 arrow length away from the bar, and the longest EMA arrow always prints 2 arrow lengths away from the bar...all regardless of if there are multiple arrows on that bar or not)

I'm trying to make it so that when you switch between stock charts you don't have to tweak the vertical offset so that it is "right" for that chart. (looks good and not huge distance between arrows)

Thanks again for the help, I understand if you don't want to try to solve this problem. I'm just trying to make the arrows look visually better and uniform from chart to chart.

Here is the code I have right now from yours, I removed a few things and mainly changed the offset variables.

Code:
# stack_arrows_01

def price = close;
def na = double.nan;

input show_average_lines = yes;
input show_crossing_arrows = yes;
input show_description_labels = yes;

# ----------------------------------
input avg1_color = 6;
# 6 = green

#hint avg1_color:  10 colors used with getcolor(). \n  0 = magenta, 1 = cyan, 2 = pink, 3 = gray, 4 = org \n  5 = red, 6 = green, 7 = dark gray, 8 = yellow, 9 = white \n    .setDefaultColor( GetColor(1) );

input avg1a_len = 3;
input avg1a_type =  AverageType.EXPONENTIAL;
def ma1a = MovingAverage(avg1a_type, price, avg1a_len);

input avg1b_len = 8;
input avg1b_type =  AverageType.EXPONENTIAL;
def ma1b = MovingAverage(avg1b_type, price, avg1b_len);

plot pma1a = if show_average_lines then ma1a else na;
#pma1a.SetDefaultColor(Color.Green);
pma1a.SetDefaultColor(getcolor(avg1_color));
#pma1a.SetLineWeight(1);

plot pma1b = if show_average_lines then ma1b else na;
#pma1b.SetDefaultColor(Color.Green);
pma1b.SetDefaultColor(getcolor(avg1_color));
pma1b.SetStyle(Curve.MEDIUM_DASH);
#pma1b.SetLineWeight(1);

# ----------------------------------
input avg2_color = 0;

input avg2a_len = 9;
input avg2a_type =  AverageType.EXPONENTIAL;
def ma2a = MovingAverage(avg2a_type, price, avg2a_len);

input avg2b_len = 13;
input avg2b_type =  AverageType.EXPONENTIAL;
def ma2b = MovingAverage(avg2b_type, price, avg2b_len);

plot pma2a = if show_average_lines then ma2a else na;
pma2a.SetDefaultColor(getcolor(avg2_color));
#pma2a.SetLineWeight(1);

plot pma2b = if show_average_lines then ma2b else na;
pma2b.SetDefaultColor(getcolor(avg2_color));
pma2b.SetStyle(Curve.MEDIUM_DASH);
#pma2b.SetLineWeight(1);

# ----------------------------------
input avg3_color = 8;

input avg3a_len = 8;
input avg3a_type =  AverageType.EXPONENTIAL;
def ma3a = MovingAverage(avg3a_type, price, avg3a_len);

input avg3b_len = 21;
input avg3b_type =  AverageType.EXPONENTIAL;
def ma3b = MovingAverage(avg3b_type, price, avg3b_len);

plot pma3a = if show_average_lines then ma3a else na;
pma3a.SetDefaultColor(getcolor(avg3_color));
#pma3a.SetLineWeight(1);

plot pma3b = if show_average_lines then ma3b else na;
pma3b.SetDefaultColor(getcolor(avg3_color));
pma3b.SetStyle(Curve.MEDIUM_DASH);
#pma3b.SetLineWeight(1);

# --------------------------------------
# check if an avg pair has crossed
def x1u = (ma1a crosses above ma1b);
def x1d = (ma1a crosses below ma1b);
def x2u = (ma2a crosses above ma2b);
def x2d = (ma2a crosses below ma2b);
def x3u = (ma3a crosses above ma3b);
def x3d = (ma3a crosses below ma3b);
# ------------------------------------

input arrow_size = 2;

# avg1 arrow is closest to bar , avg3 arrow is farthest from bar
# ------------------------------------

def adj = 0;
# calc vertical placement for arrows
def arrow3dwn = if !x3d then na else high + (.001 * high);
def arrow2dwn = if !x2d then na else high + (.0005 * high);
def arrow1dwn = if !x1d then na else high + (.0001 * high);

def arrow1up = if !x1u then na else low - (.0001 * high);
def arrow2up = if !x2u then na else low - (.0005 * high);
def arrow3up = if !x3u then na else low - (.001 * high);


# plot arrows for crossings, stacked if more than 1
plot pma3xdwn = if show_crossing_arrows then arrow3dwn else na;
plot pma2xdwn = if show_crossing_arrows then arrow2dwn else na;
plot pma1xdwn = if show_crossing_arrows then arrow1dwn else na;
plot pma1xup = if show_crossing_arrows then arrow1up else na;
plot pma2xup = if show_crossing_arrows then arrow2up else na;
plot pma3xup = if show_crossing_arrows then arrow3up else na;

pma3xdwn.SetPaintingStrategy(PaintingStrategy.ARROW_DOWN);
pma2xdwn.SetPaintingStrategy(PaintingStrategy.ARROW_DOWN);
pma1xdwn.SetPaintingStrategy(PaintingStrategy.ARROW_DOWN);
pma1xup.SetPaintingStrategy(PaintingStrategy.ARROW_up);
pma2xup.SetPaintingStrategy(PaintingStrategy.ARROW_up);
pma3xup.SetPaintingStrategy(PaintingStrategy.ARROW_up);

pma3xdwn.SetDefaultColor(getcolor(avg3_color));
pma2xdwn.SetDefaultColor(getcolor(avg2_color));
pma1xdwn.SetDefaultColor(getcolor(avg1_color));
pma1xup.SetDefaultColor(getcolor(avg1_color));
pma2xup.SetDefaultColor(getcolor(avg2_color));
pma3xup.SetDefaultColor(getcolor(avg3_color));

pma3xdwn.hidebubble();
pma2xdwn.hidebubble();
pma1xdwn.hidebubble();
pma1xup.hidebubble();
pma2xup.hidebubble();
pma3xup.hidebubble();

pma3xdwn.setlineweight(arrow_size);
pma2xdwn.setlineweight(arrow_size);
pma1xdwn.setlineweight(arrow_size);
pma1xup.setlineweight(arrow_size);
pma2xup.setlineweight(arrow_size);
pma3xup.setlineweight(arrow_size);

# ----------------------------------------
addlabel(show_description_labels, "avg1  " + avg1a_len + "/" + avg1b_len, getcolor(avg1_color));
addlabel(show_description_labels, "avg2  " + avg2a_len + "/" + avg2b_len, getcolor(avg2_color));
addlabel(show_description_labels, "avg3  " + avg3a_len + "/" + avg3b_len, getcolor(avg3_color));

# -------------------------------------------

input test_ticksize_label = no;
addlabel( test_ticksize_label , " ticksize " + ticksize(), color.cyan);
# -----------------------------------------

# https://tlc.thinkorswim.com/center/reference/thinkScript/Constants/AverageType
#  EXPONENTIAL
#  HULL
#  SIMPLE
#  WEIGHTED
#  WILDERS

# https://tlc.thinkorswim.com/center/reference/thinkScript/functions/look---feel/getcolor
# getcolors
#

From this code I got these results:

As you can see $MAPS is still charting the arrows closer together/overlapping slightly since they are plotting based on a smaller stock price
and $AAPL is still charting arrows further apart, but better than before, because they are based on a larger stock price

 
Having a slight problem on further testing:

For different tickers then offset size needs to be different or arrows will / will not overlap, sometimes the space between arrows becomes huge

$MAPS, vertical factor set to 1, plenty of space between arrows

$TSLA, vertical factor also 1, arrows are overlapping each other


I also noticed that the vertical factor applies to all arrows, that being: when you make the vertical factor 50 its offsets all arrows by 50 so that even the bars with only one arrow have a huge offset. looks weird

it seems that the vertical size applies to all arrows, and grows exponentially the larger you make the number

is there a way to make is so that the vertical factor will only offset ONE arrow if it is overlaid on top of a bar that already has 1
there is another vertical adjustment variable. i left it as a def.
def adj = 0;

try changing it to
def adj = 1;
to move the arrows closer to the bar
 
Ok, so I'm not good with thinkscript and legit have never learned how to code with it this is just what I've observed through changing variables / values. The arrows are non-boolean and are thus basing their vertical offset on the price of that ticker that you are charting. This means that for the $AAPL ($179) chart, the arrows are plotting based on a much higher price than say if the arrows were plotting on a chart of $MAPS ($6.00). This means that the vertical offset of the arrows will always have to be changed when you switch between stocks that have a drastically different price.

This problem could be solved simply by making is so that the arrows always plot at a certain distance from the BAR, not necessarily the price of the bar. So...standardizing the unit of measurement across all charts of a stocks, not based on price, but based on visual size of the bar. Also to make it simpler, you can have it so that the longest EMA crossover arrow will always plot a certain distance (the furthest) from the bar, even if it is the only arrow on that bar. Essentially the arrow of a specific crossover will always plot at a certain visual distance from the bar it is on (ie. the shortest EMA crossover always plots near the bar, the middle EMA arrow always plots about 1 arrow length away from the bar, and the longest EMA arrow always prints 2 arrow lengths away from the bar...all regardless of if there are multiple arrows on that bar or not)

I'm trying to make it so that when you switch between stock charts you don't have to tweak the vertical offset so that it is "right" for that chart. (looks good and not huge distance between arrows)

Thanks again for the help, I understand if you don't want to try to solve this problem. I'm just trying to make the arrows look visually better and uniform from chart to chart.

Here is the code I have right now from yours, I removed a few things and mainly changed the offset variables.

Code:
# stack_arrows_01

def price = close;
def na = double.nan;

input show_average_lines = yes;
input show_crossing_arrows = yes;
input show_description_labels = yes;

# ----------------------------------
input avg1_color = 6;
# 6 = green

#hint avg1_color:  10 colors used with getcolor(). \n  0 = magenta, 1 = cyan, 2 = pink, 3 = gray, 4 = org \n  5 = red, 6 = green, 7 = dark gray, 8 = yellow, 9 = white \n    .setDefaultColor( GetColor(1) );

input avg1a_len = 3;
input avg1a_type =  AverageType.EXPONENTIAL;
def ma1a = MovingAverage(avg1a_type, price, avg1a_len);

input avg1b_len = 8;
input avg1b_type =  AverageType.EXPONENTIAL;
def ma1b = MovingAverage(avg1b_type, price, avg1b_len);

plot pma1a = if show_average_lines then ma1a else na;
#pma1a.SetDefaultColor(Color.Green);
pma1a.SetDefaultColor(getcolor(avg1_color));
#pma1a.SetLineWeight(1);

plot pma1b = if show_average_lines then ma1b else na;
#pma1b.SetDefaultColor(Color.Green);
pma1b.SetDefaultColor(getcolor(avg1_color));
pma1b.SetStyle(Curve.MEDIUM_DASH);
#pma1b.SetLineWeight(1);

# ----------------------------------
input avg2_color = 0;

input avg2a_len = 9;
input avg2a_type =  AverageType.EXPONENTIAL;
def ma2a = MovingAverage(avg2a_type, price, avg2a_len);

input avg2b_len = 13;
input avg2b_type =  AverageType.EXPONENTIAL;
def ma2b = MovingAverage(avg2b_type, price, avg2b_len);

plot pma2a = if show_average_lines then ma2a else na;
pma2a.SetDefaultColor(getcolor(avg2_color));
#pma2a.SetLineWeight(1);

plot pma2b = if show_average_lines then ma2b else na;
pma2b.SetDefaultColor(getcolor(avg2_color));
pma2b.SetStyle(Curve.MEDIUM_DASH);
#pma2b.SetLineWeight(1);

# ----------------------------------
input avg3_color = 8;

input avg3a_len = 8;
input avg3a_type =  AverageType.EXPONENTIAL;
def ma3a = MovingAverage(avg3a_type, price, avg3a_len);

input avg3b_len = 21;
input avg3b_type =  AverageType.EXPONENTIAL;
def ma3b = MovingAverage(avg3b_type, price, avg3b_len);

plot pma3a = if show_average_lines then ma3a else na;
pma3a.SetDefaultColor(getcolor(avg3_color));
#pma3a.SetLineWeight(1);

plot pma3b = if show_average_lines then ma3b else na;
pma3b.SetDefaultColor(getcolor(avg3_color));
pma3b.SetStyle(Curve.MEDIUM_DASH);
#pma3b.SetLineWeight(1);

# --------------------------------------
# check if an avg pair has crossed
def x1u = (ma1a crosses above ma1b);
def x1d = (ma1a crosses below ma1b);
def x2u = (ma2a crosses above ma2b);
def x2d = (ma2a crosses below ma2b);
def x3u = (ma3a crosses above ma3b);
def x3d = (ma3a crosses below ma3b);
# ------------------------------------

input arrow_size = 2;

# avg1 arrow is closest to bar , avg3 arrow is farthest from bar
# ------------------------------------

def adj = 0;
# calc vertical placement for arrows
def arrow3dwn = if !x3d then na else high + (.001 * high);
def arrow2dwn = if !x2d then na else high + (.0005 * high);
def arrow1dwn = if !x1d then na else high + (.0001 * high);

def arrow1up = if !x1u then na else low - (.0001 * high);
def arrow2up = if !x2u then na else low - (.0005 * high);
def arrow3up = if !x3u then na else low - (.001 * high);


# plot arrows for crossings, stacked if more than 1
plot pma3xdwn = if show_crossing_arrows then arrow3dwn else na;
plot pma2xdwn = if show_crossing_arrows then arrow2dwn else na;
plot pma1xdwn = if show_crossing_arrows then arrow1dwn else na;
plot pma1xup = if show_crossing_arrows then arrow1up else na;
plot pma2xup = if show_crossing_arrows then arrow2up else na;
plot pma3xup = if show_crossing_arrows then arrow3up else na;

pma3xdwn.SetPaintingStrategy(PaintingStrategy.ARROW_DOWN);
pma2xdwn.SetPaintingStrategy(PaintingStrategy.ARROW_DOWN);
pma1xdwn.SetPaintingStrategy(PaintingStrategy.ARROW_DOWN);
pma1xup.SetPaintingStrategy(PaintingStrategy.ARROW_up);
pma2xup.SetPaintingStrategy(PaintingStrategy.ARROW_up);
pma3xup.SetPaintingStrategy(PaintingStrategy.ARROW_up);

pma3xdwn.SetDefaultColor(getcolor(avg3_color));
pma2xdwn.SetDefaultColor(getcolor(avg2_color));
pma1xdwn.SetDefaultColor(getcolor(avg1_color));
pma1xup.SetDefaultColor(getcolor(avg1_color));
pma2xup.SetDefaultColor(getcolor(avg2_color));
pma3xup.SetDefaultColor(getcolor(avg3_color));

pma3xdwn.hidebubble();
pma2xdwn.hidebubble();
pma1xdwn.hidebubble();
pma1xup.hidebubble();
pma2xup.hidebubble();
pma3xup.hidebubble();

pma3xdwn.setlineweight(arrow_size);
pma2xdwn.setlineweight(arrow_size);
pma1xdwn.setlineweight(arrow_size);
pma1xup.setlineweight(arrow_size);
pma2xup.setlineweight(arrow_size);
pma3xup.setlineweight(arrow_size);

# ----------------------------------------
addlabel(show_description_labels, "avg1  " + avg1a_len + "/" + avg1b_len, getcolor(avg1_color));
addlabel(show_description_labels, "avg2  " + avg2a_len + "/" + avg2b_len, getcolor(avg2_color));
addlabel(show_description_labels, "avg3  " + avg3a_len + "/" + avg3b_len, getcolor(avg3_color));

# -------------------------------------------

input test_ticksize_label = no;
addlabel( test_ticksize_label , " ticksize " + ticksize(), color.cyan);
# -----------------------------------------

# https://tlc.thinkorswim.com/center/reference/thinkScript/Constants/AverageType
#  EXPONENTIAL
#  HULL
#  SIMPLE
#  WEIGHTED
#  WILDERS

# https://tlc.thinkorswim.com/center/reference/thinkScript/functions/look---feel/getcolor
# getcolors
#

From this code I got these results:

As you can see $MAPS is still charting the arrows closer together/overlapping slightly since they are plotting based on a smaller stock price
and $AAPL is still charting arrows further apart, but better than before, because they are based on a larger stock price


i have always used a tiny number for vertical offsets, like you used, like 0.001.
the ticksize variable, mentiined in this thread, seemed interesting and i thought it would work close enough.
i don't think there is a perfect formula for creating the desired spacing of shapes. the high low range on similarly priced stocks will be different, altering the drawn spacings. then if you zoom in , there is no way to account for that.
 
Ok, so I'm not good with thinkscript and legit have never learned how to code with it this is just what I've observed through changing variables / values. The arrows are non-boolean and are thus basing their vertical offset on the price of that ticker that you are charting. This means that for the $AAPL ($179) chart, the arrows are plotting based on a much higher price than say if the arrows were plotting on a chart of $MAPS ($6.00). This means that the vertical offset of the arrows will always have to be changed when you switch between stocks that have a drastically different price.

This problem could be solved simply by making is so that the arrows always plot at a certain distance from the BAR, not necessarily the price of the bar. So...standardizing the unit of measurement across all charts of a stocks, not based on price, but based on visual size of the bar. Also to make it simpler, you can have it so that the longest EMA crossover arrow will always plot a certain distance (the furthest) from the bar, even if it is the only arrow on that bar. Essentially the arrow of a specific crossover will always plot at a certain visual distance from the bar it is on (ie. the shortest EMA crossover always plots near the bar, the middle EMA arrow always plots about 1 arrow length away from the bar, and the longest EMA arrow always prints 2 arrow lengths away from the bar...all regardless of if there are multiple arrows on that bar or not)

I'm trying to make it so that when you switch between stock charts you don't have to tweak the vertical offset so that it is "right" for that chart. (looks good and not huge distance between arrows)

Thanks again for the help, I understand if you don't want to try to solve this problem. I'm just trying to make the arrows look visually better and uniform from chart to chart.

Here is the code I have right now from yours, I removed a few things and mainly changed the offset variables.

Code:
# stack_arrows_01

def price = close;
def na = double.nan;

input show_average_lines = yes;
input show_crossing_arrows = yes;
input show_description_labels = yes;

# ----------------------------------
input avg1_color = 6;
# 6 = green

#hint avg1_color:  10 colors used with getcolor(). \n  0 = magenta, 1 = cyan, 2 = pink, 3 = gray, 4 = org \n  5 = red, 6 = green, 7 = dark gray, 8 = yellow, 9 = white \n    .setDefaultColor( GetColor(1) );

input avg1a_len = 3;
input avg1a_type =  AverageType.EXPONENTIAL;
def ma1a = MovingAverage(avg1a_type, price, avg1a_len);

input avg1b_len = 8;
input avg1b_type =  AverageType.EXPONENTIAL;
def ma1b = MovingAverage(avg1b_type, price, avg1b_len);

plot pma1a = if show_average_lines then ma1a else na;
#pma1a.SetDefaultColor(Color.Green);
pma1a.SetDefaultColor(getcolor(avg1_color));
#pma1a.SetLineWeight(1);

plot pma1b = if show_average_lines then ma1b else na;
#pma1b.SetDefaultColor(Color.Green);
pma1b.SetDefaultColor(getcolor(avg1_color));
pma1b.SetStyle(Curve.MEDIUM_DASH);
#pma1b.SetLineWeight(1);

# ----------------------------------
input avg2_color = 0;

input avg2a_len = 9;
input avg2a_type =  AverageType.EXPONENTIAL;
def ma2a = MovingAverage(avg2a_type, price, avg2a_len);

input avg2b_len = 13;
input avg2b_type =  AverageType.EXPONENTIAL;
def ma2b = MovingAverage(avg2b_type, price, avg2b_len);

plot pma2a = if show_average_lines then ma2a else na;
pma2a.SetDefaultColor(getcolor(avg2_color));
#pma2a.SetLineWeight(1);

plot pma2b = if show_average_lines then ma2b else na;
pma2b.SetDefaultColor(getcolor(avg2_color));
pma2b.SetStyle(Curve.MEDIUM_DASH);
#pma2b.SetLineWeight(1);

# ----------------------------------
input avg3_color = 8;

input avg3a_len = 8;
input avg3a_type =  AverageType.EXPONENTIAL;
def ma3a = MovingAverage(avg3a_type, price, avg3a_len);

input avg3b_len = 21;
input avg3b_type =  AverageType.EXPONENTIAL;
def ma3b = MovingAverage(avg3b_type, price, avg3b_len);

plot pma3a = if show_average_lines then ma3a else na;
pma3a.SetDefaultColor(getcolor(avg3_color));
#pma3a.SetLineWeight(1);

plot pma3b = if show_average_lines then ma3b else na;
pma3b.SetDefaultColor(getcolor(avg3_color));
pma3b.SetStyle(Curve.MEDIUM_DASH);
#pma3b.SetLineWeight(1);

# --------------------------------------
# check if an avg pair has crossed
def x1u = (ma1a crosses above ma1b);
def x1d = (ma1a crosses below ma1b);
def x2u = (ma2a crosses above ma2b);
def x2d = (ma2a crosses below ma2b);
def x3u = (ma3a crosses above ma3b);
def x3d = (ma3a crosses below ma3b);
# ------------------------------------

input arrow_size = 2;

# avg1 arrow is closest to bar , avg3 arrow is farthest from bar
# ------------------------------------

def adj = 0;
# calc vertical placement for arrows
def arrow3dwn = if !x3d then na else high + (.001 * high);
def arrow2dwn = if !x2d then na else high + (.0005 * high);
def arrow1dwn = if !x1d then na else high + (.0001 * high);

def arrow1up = if !x1u then na else low - (.0001 * high);
def arrow2up = if !x2u then na else low - (.0005 * high);
def arrow3up = if !x3u then na else low - (.001 * high);


# plot arrows for crossings, stacked if more than 1
plot pma3xdwn = if show_crossing_arrows then arrow3dwn else na;
plot pma2xdwn = if show_crossing_arrows then arrow2dwn else na;
plot pma1xdwn = if show_crossing_arrows then arrow1dwn else na;
plot pma1xup = if show_crossing_arrows then arrow1up else na;
plot pma2xup = if show_crossing_arrows then arrow2up else na;
plot pma3xup = if show_crossing_arrows then arrow3up else na;

pma3xdwn.SetPaintingStrategy(PaintingStrategy.ARROW_DOWN);
pma2xdwn.SetPaintingStrategy(PaintingStrategy.ARROW_DOWN);
pma1xdwn.SetPaintingStrategy(PaintingStrategy.ARROW_DOWN);
pma1xup.SetPaintingStrategy(PaintingStrategy.ARROW_up);
pma2xup.SetPaintingStrategy(PaintingStrategy.ARROW_up);
pma3xup.SetPaintingStrategy(PaintingStrategy.ARROW_up);

pma3xdwn.SetDefaultColor(getcolor(avg3_color));
pma2xdwn.SetDefaultColor(getcolor(avg2_color));
pma1xdwn.SetDefaultColor(getcolor(avg1_color));
pma1xup.SetDefaultColor(getcolor(avg1_color));
pma2xup.SetDefaultColor(getcolor(avg2_color));
pma3xup.SetDefaultColor(getcolor(avg3_color));

pma3xdwn.hidebubble();
pma2xdwn.hidebubble();
pma1xdwn.hidebubble();
pma1xup.hidebubble();
pma2xup.hidebubble();
pma3xup.hidebubble();

pma3xdwn.setlineweight(arrow_size);
pma2xdwn.setlineweight(arrow_size);
pma1xdwn.setlineweight(arrow_size);
pma1xup.setlineweight(arrow_size);
pma2xup.setlineweight(arrow_size);
pma3xup.setlineweight(arrow_size);

# ----------------------------------------
addlabel(show_description_labels, "avg1  " + avg1a_len + "/" + avg1b_len, getcolor(avg1_color));
addlabel(show_description_labels, "avg2  " + avg2a_len + "/" + avg2b_len, getcolor(avg2_color));
addlabel(show_description_labels, "avg3  " + avg3a_len + "/" + avg3b_len, getcolor(avg3_color));

# -------------------------------------------

input test_ticksize_label = no;
addlabel( test_ticksize_label , " ticksize " + ticksize(), color.cyan);
# -----------------------------------------

# https://tlc.thinkorswim.com/center/reference/thinkScript/Constants/AverageType
#  EXPONENTIAL
#  HULL
#  SIMPLE
#  WEIGHTED
#  WILDERS

# https://tlc.thinkorswim.com/center/reference/thinkScript/functions/look---feel/getcolor
# getcolors
#

From this code I got these results:

As you can see $MAPS is still charting the arrows closer together/overlapping slightly since they are plotting based on a smaller stock price
and $AAPL is still charting arrows further apart, but better than before, because they are based on a larger stock price

@lucprokop Another way you could try is to use a measure of volatility as the offset, i.e., an ATR() value -
low - 1 * ATR(length = 20, averageType = averageType.SIMPLE) might help smooth out the offset differences.
 
@lucprokop Another way you could try is to use a measure of volatility as the offset, i.e., an ATR() value -
low - 1 * ATR(length = 20, averageType = averageType.SIMPLE) might help smooth out the offset differences.

I could kiss you right now...


ATR smoothing worked very well, now the arrows do not have huge spaces when moving from chart to chart.

Thanks for all the help everyone.
 
So I was experimenting with EMA crosses and clouds and found a system that I think is good. It involves using the 3/8, 9/13, and 8/21 EMA cross. Each time there is a crosses of the EMAs the indicator plots an arrow (up arrow for fast>slow, down arrow for slow>fast). The problem that I am having is that sometimes the arrows from two separate crosses will plot directly over one another on the chart and I have to hover over a previous arrow of a certain cross to show which one triggered. Basically I have been looking everywhere to figured out how to offset where arrows will plot for a certain cross. For example, if the 8/13 cross and the 8/21 cross both happen on the same bar, the 8/21 cross will be offset just enough so that they don't plot directly on top of each other. I've attached photos and the script. What edits do I need to make to the script to fix this issue.

Here are two arrows plotting directly over each other on the same bar:
9/13 EMA Cross Arrow shown here
3/8 EMA Cross Arrow only shows when i hover mouse over it

Here is where I want to move the 9/13 cross arrow:

Here is the code:
Code:
input price = close;#hint price: The price used to calculate the crossover. <b>(Default is CLOSE)</b>
input fastLength = 8;#hint fastLength: The number of bars used to calculate the fast moving average. <b>(Default is 3)</b>
input slowLength = 21;#hint slowLength: The number of bars used to calculate the slow moving average. <b>(Default is 8)</b>
input slowAvgType = {default Simple, Exponential, Weighted, Wilders, Hull};#hint slowAvgType: Type of the fast moving average to be used for calculation. <b>(Default is Expontential)</b>
input fastAvgType = {default Simple, Exponential, Weighted, Wilders, Hull};#hint fastAvgType: Type of the fast moving average to be used for calculation. <b>(Default is Exponential)</b>
Input DoArrows = no;#hint DoArrows:Yes shows arrows to define crosses
Input DoPlots = yes;#hint DoPlots: Yes shows MA plots to define crosses. Default is 'YES'
Input DoAlerts = No;#hint DoAlerts:No turns off alerts
Assert( fastLength < slowLength, "fastLength ["+fastLength+"] must be less than slowLength["+slowLength+"]");

def fastAvg;
switch (slowAvgType) {
case Simple:
    fastAvg = Average(price, fastLength);
case Exponential:
    fastAvg = ExpAverage(price, fastLength);
case Weighted:
    fastAvg = wma(price, fastLength);
case Wilders:
    fastAvg = WildersAverage(price, fastLength);
case Hull:
    fastAvg = HullMovingAvg(price, fastLength);
}

def slowAvg;
switch (fastAvgType) {
case Simple:
    slowAvg = Average(price, slowLength);
case Exponential:
    slowAvg = ExpAverage(price, slowLength);
case Weighted:
    slowAvg = wma(price, slowLength);
case Wilders:
    slowAvg = WildersAverage(price, slowLength);
case Hull:
    slowAvg = HullMovingAvg(price, slowLength);
}

plot signalXup = If DoArrows Then crosses(fastAvg, slowAvg, CrossingDirection.above) else Double.nan;
signalXup.SetDefaultColor(Color.pink);
signalXup.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_UP);
signalXup.SetLineWeight(3);

plot signalXdn =  If DoArrows Then crosses(fastAvg, slowAvg, CrossingDirection.below) else Double.nan;
signalXdn.SetDefaultColor(Color.Green);
signalXdn.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_DOWN);
signalXdn.SetLineWeight(3);
TOS presents the arrows in the order by which they're coded; so, code the first arrow as having a LineWeight as 5. Have the subsequent arrows with smaller LineWeights--like 3, then 1. The result will be that the 1st, largest arrow will be overlayed by the next, smaller arrow; and, the last arrow will overlay the previous two. If you do the opposite, then the largest overlays the smaller arrow(s) and you will still have the same issue. Having different colors for your arrows makes a significant difference, too. I've found that WHITE is the best for the largest arrow. I'm sorry I didn't have time to code for you; however, this information should make a huge difference! Merry Christmas to All!
 
Thanks.. IT doesn't load any studies or charts. Just the default workspace. ! Can you share the updated code in this forum ?
was in the middle of taking finals, sorry for the late response

Code:
# stack_arrows_01

def price = close;
def na = double.nan;

input show_average_lines = yes;
input show_crossing_arrows = yes;
input show_description_labels = yes;

# ----------------------------------
input avg1_color = 6;
# 6 = green

#hint avg1_color:  10 colors used with getcolor(). \n  0 = magenta, 1 = cyan, 2 = pink, 3 = gray, 4 = org \n  5 = red, 6 = green, 7 = dark gray, 8 = yellow, 9 = white \n    .setDefaultColor( GetColor(1) );

input avg1a_len = 3;
input avg1a_type =  AverageType.EXPONENTIAL;
def ma1a = MovingAverage(avg1a_type, price, avg1a_len);

input avg1b_len = 8;
input avg1b_type =  AverageType.EXPONENTIAL;
def ma1b = MovingAverage(avg1b_type, price, avg1b_len);

plot pma1a = if show_average_lines then ma1a else na;
#pma1a.SetDefaultColor(Color.Green);
pma1a.SetDefaultColor(getcolor(avg1_color));
#pma1a.SetLineWeight(1);

plot pma1b = if show_average_lines then ma1b else na;
#pma1b.SetDefaultColor(Color.Green);
pma1b.SetDefaultColor(getcolor(avg1_color));
pma1b.SetStyle(Curve.MEDIUM_DASH);
#pma1b.SetLineWeight(1);

# ----------------------------------
input avg2_color = 0;

input avg2a_len = 9;
input avg2a_type =  AverageType.EXPONENTIAL;
def ma2a = MovingAverage(avg2a_type, price, avg2a_len);

input avg2b_len = 13;
input avg2b_type =  AverageType.EXPONENTIAL;
def ma2b = MovingAverage(avg2b_type, price, avg2b_len);

plot pma2a = if show_average_lines then ma2a else na;
pma2a.SetDefaultColor(getcolor(avg2_color));
#pma2a.SetLineWeight(1);

plot pma2b = if show_average_lines then ma2b else na;
pma2b.SetDefaultColor(getcolor(avg2_color));
pma2b.SetStyle(Curve.MEDIUM_DASH);
#pma2b.SetLineWeight(1);

# ----------------------------------
input avg3_color = 8;

input avg3a_len = 8;
input avg3a_type =  AverageType.EXPONENTIAL;
def ma3a = MovingAverage(avg3a_type, price, avg3a_len);

input avg3b_len = 21;
input avg3b_type =  AverageType.EXPONENTIAL;
def ma3b = MovingAverage(avg3b_type, price, avg3b_len);

plot pma3a = if show_average_lines then ma3a else na;
pma3a.SetDefaultColor(getcolor(avg3_color));
#pma3a.SetLineWeight(1);

plot pma3b = if show_average_lines then ma3b else na;
pma3b.SetDefaultColor(getcolor(avg3_color));
pma3b.SetStyle(Curve.MEDIUM_DASH);
#pma3b.SetLineWeight(1);

# --------------------------------------
# check if an avg pair has crossed
def x1u = (ma1a crosses above ma1b);
def x1d = (ma1a crosses below ma1b);
def x2u = (ma2a crosses above ma2b);
def x2d = (ma2a crosses below ma2b);
def x3u = (ma3a crosses above ma3b);
def x3d = (ma3a crosses below ma3b);
# ------------------------------------

input arrow_size = 2;
input arrow_vertical_factor = 10;
def vert = (ticksize() * arrow_vertical_factor * arrow_size);

# avg1 arrow is closest to bar , avg3 arrow is farthest from bar
# ------------------------------------


# calc vertical placement for arrows
def arrow3dwn = if !x3d then na else high +  .3 * ATR(length = 20, averageType = averageType.SIMPLE);
def arrow2dwn = if !x2d then na else high +  .15 * ATR(length = 20, averageType = averageType.SIMPLE);
def arrow1dwn = if !x1d then na else high +  0 * ATR(length = 20, averageType = averageType.SIMPLE);

def arrow1up = if !x1u then na else low - 0 * ATR(length = 20, averageType = averageType.SIMPLE);
def arrow2up = if !x2u then na else low - .15 * ATR(length = 20, averageType = averageType.SIMPLE);
def arrow3up = if !x3u then na else low - .3 * ATR(length = 20, averageType = averageType.SIMPLE);


# plot arrows for crossings, stacked if more than 1
plot pma3xdwn = if show_crossing_arrows then arrow3dwn else na;
plot pma2xdwn = if show_crossing_arrows then arrow2dwn else na;
plot pma1xdwn = if show_crossing_arrows then arrow1dwn else na;
plot pma1xup = if show_crossing_arrows then arrow1up else na;
plot pma2xup = if show_crossing_arrows then arrow2up else na;
plot pma3xup = if show_crossing_arrows then arrow3up else na;

pma3xdwn.SetPaintingStrategy(PaintingStrategy.ARROW_DOWN);
pma2xdwn.SetPaintingStrategy(PaintingStrategy.ARROW_DOWN);
pma1xdwn.SetPaintingStrategy(PaintingStrategy.ARROW_DOWN);
pma1xup.SetPaintingStrategy(PaintingStrategy.ARROW_up);
pma2xup.SetPaintingStrategy(PaintingStrategy.ARROW_up);
pma3xup.SetPaintingStrategy(PaintingStrategy.ARROW_up);

pma3xdwn.SetDefaultColor(getcolor(avg3_color));
pma2xdwn.SetDefaultColor(getcolor(avg2_color));
pma1xdwn.SetDefaultColor(getcolor(avg1_color));
pma1xup.SetDefaultColor(getcolor(avg1_color));
pma2xup.SetDefaultColor(getcolor(avg2_color));
pma3xup.SetDefaultColor(getcolor(avg3_color));

pma3xdwn.hidebubble();
pma2xdwn.hidebubble();
pma1xdwn.hidebubble();
pma1xup.hidebubble();
pma2xup.hidebubble();
pma3xup.hidebubble();

pma3xdwn.setlineweight(arrow_size);
pma2xdwn.setlineweight(arrow_size);
pma1xdwn.setlineweight(arrow_size);
pma1xup.setlineweight(arrow_size);
pma2xup.setlineweight(arrow_size);
pma3xup.setlineweight(arrow_size);

# ----------------------------------------
addlabel(show_description_labels, "avg1  " + avg1a_len + "/" + avg1b_len, getcolor(avg1_color));
addlabel(show_description_labels, "avg2  " + avg2a_len + "/" + avg2b_len, getcolor(avg2_color));
addlabel(show_description_labels, "avg3  " + avg3a_len + "/" + avg3b_len, getcolor(avg3_color));

# -------------------------------------------

input test_ticksize_label = no;
addlabel( test_ticksize_label , " ticksize " + ticksize(), color.cyan);
# -----------------------------------------

# https://tlc.thinkorswim.com/center/reference/thinkScript/Constants/AverageType
#  EXPONENTIAL
#  HULL
#  SIMPLE
#  WEIGHTED
#  WILDERS

# https://tlc.thinkorswim.com/center/reference/thinkScript/functions/look---feel/getcolor
# getcolors
#
 
There is any way to show the arrow with more space from the candle, I have other indicator and and the arrows can be on top of each other.
Thanks
 
There is any way to show the arrow with more space from the candle, I have other indicator and and the arrows can be on top of each other.
Thanks
I have the same question, I've been googling like crazy and I haven't found the answer. The only workaround I have found is to use a vertical line for one indicator, and an arrow for the other. Now, if you have a 3rd, I don't know how to show that one.
 
There is any way to show the arrow with more space from the candle, I have other indicator and and the arrows can be on top of each other.
Thanks
I have the same question, I've been googling like crazy and I haven't found the answer. The only workaround I have found is to use a vertical line for one indicator, and an arrow for the other. Now, if you have a 3rd, I don't know how to show that one.
Moved your question to this thread. Many examples of how to space arrows
 

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

Thread starter Similar threads Forum Replies Date
halcyonguy MTF Arrows: choose 1 of 3 sets, of 5 periods Tutorials 4

Similar threads

Not the exact question you're looking for?

Start a new thread and receive assistance from our community.

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