price roc for line

Glefdar

Active member
Draw a straight line between two points based on start/end variables and then calculate price rate of change over the bar length of the line

Hello all, I will do my best to explain clearly what I want to do:

I want to have two conditions that define the start and end point for a straight line to be drawn. For example, start_condition could be that RSI[1] is not oversold (meaning is not below 30) and RSI[0] is oversold, and end_condition could be that RSI[1] is oversold and RSI[0] is not oversold. (This is just an example to illustrate what I mean by a start condition and an end condition for the beginning candle and the ending candle that are used for drawing the straight line.)

Suppose in this above example that RSI stays oversold for 16 minutes on a 1 minute chart. That will mean that the line’s bar length is going to be 17 bars long (since the final bar will include the bar in which RSI crosses above the oversold threshold).

In addition to the straight line drawn on the chart between the start and end points, I also want the price rate of change calculated over the 17 bars (in this example case) that constitute the length of the line.

I’m not sure if this is an easy or difficult request. It would be ideal if each subsequent drawn line and rate of change calculation did not overwrite or repaint the previous drawn line and ROC calculation, at least up to some maximum limit of something like 5 lines. To not waste overwriting one of the lines based on a set of bars that was too small to form a significant line (e.g. in our example, this would be like if the RSI was only oversold for two bars consecutively), maybe it would also be necessary to have a minimum bar length of how many bars must occur between the start and end conditions in order for them to be valid (I think this would cause some lag for plotting the line, but maybe that is fine if the intervening bar requirement is a small number).

I’m not sure about the best way to go about this and think it may be more complicated than it first seems, but maybe I’m over-complicating it. Is my explanation clear and is there a simple way to do this? Many thanks to anyone who can offer some insight.

Edit: I should clarify that I think it would also be useful for the current line that is still unfinished (meaning the start condition has been met but an end condition has not been met yet) to plot in a different color and calculate the rate of change on an ongoing basis until the end condition occurs at which point the color appears like the other lines and also the rate of change calculation becomes set in stone.
 
Last edited:
Draw a straight line between two points based on start/end variables and then calculate price rate of change over the bar length of the line

Hello all, I will do my best to explain clearly what I want to do:

I want to have two conditions that define the start and end point for a straight line to be drawn. For example, start_condition could be that RSI[1] is not oversold (meaning is not below 30) and RSI[0] is oversold, and end_condition could be that RSI[1] is oversold and RSI[0] is not oversold. (This is just an example to illustrate what I mean by a start condition and an end condition for the beginning candle and the ending candle that are used for drawing the straight line.)

Suppose in this above example that RSI stays oversold for 16 minutes on a 1 minute chart. That will mean that the line’s bar length is going to be 17 bars long (since the final bar will include the bar in which RSI crosses above the oversold threshold).

In addition to the straight line drawn on the chart between the start and end points, I also want the price rate of change calculated over the 17 bars (in this example case) that constitute the length of the line.

I’m not sure if this is an easy or difficult request. It would be ideal if each subsequent drawn line and rate of change calculation did not overwrite or repaint the previous drawn line and ROC calculation, at least up to some maximum limit of something like 5 lines. To not waste overwriting one of the lines based on a set of bars that was too small to form a significant line (e.g. in our example, this would be like if the RSI was only oversold for two bars consecutively), maybe it would also be necessary to have a minimum bar length of how many bars must occur between the start and end conditions in order for them to be valid (I think this would cause some lag for plotting the line, but maybe that is fine if the intervening bar requirement is a small number).

I’m not sure about the best way to go about this and think it may be more complicated than it first seems, but maybe I’m over-complicating it. Is my explanation clear and is there a simple way to do this? Many thanks to anyone who can offer some insight.

Edit: I should clarify that I think it would also be useful for the current line that is still unfinished (meaning the start condition has been met but an end condition has not been met yet) to plot in a different color and calculate the rate of change on an ongoing basis until the end condition occurs at which point the color appears like the other lines and also the rate of change calculation becomes set in stone.


this uses 2 average lines and looks for them crossing, to make test signals for buying and selling.
it draws a cyan line from the close of buy signal to the close of sell signal.


Code:
# draw_line_between_2_signals_00

#https://usethinkscript.com/threads/price-roc-for-line.15921/
#draw a straight line between two points based on start/end variables and then calculate price rate of change over the bar length of the line

def na = Double.NaN;
def bn = BarNumber();


#---------------------------------------
# test data 
# for buying , short avg crossing above long avg

def price = close;
input ma1_len = 9;
input ma1_type =  AverageType.EXPONENTIAL;
def ma1 = MovingAverage(ma1_type, price, ma1_len);

input ma2_len = 33;
input ma2_type =  AverageType.EXPONENTIAL;
def ma2 = MovingAverage(ma2_type, price, ma2_len);


input show_lines = yes;
plot z1 = if show_lines then ma1 else na;
 z1.SetDefaultColor(color.light_gray);
 #z1.setlineweight(1);
 z1.HideBubble();
plot z2 = if show_lines then ma2 else na;
 z2.SetDefaultColor(color.light_gray);
 #z2.setlineweight(1);
 z2.HideBubble();


def ma1xup = (ma1 crosses above ma2);
def ma1xdwn = (ma1 crosses below ma2);

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

def long_buy = ma1xup;
def long_sell = ma1xdwn;


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


input show_buy_arrows = yes;
def arroff = 22;
def y = arroff * ticksize();

plot zbuy = if show_buy_arrows and long_buy then ma2 else na;
zbuy.SetPaintingStrategy(PaintingStrategy.ARROW_UP);
zbuy.SetDefaultColor(Color.green);
zbuy.setlineweight(3);
zbuy.hidebubble();


input show_sell_arrows = yes;
plot zsell = if show_sell_arrows and long_sell then ma2 else na;
zsell.SetPaintingStrategy(PaintingStrategy.ARROW_DOWN);
zsell.SetDefaultColor(Color.red);
zsell.setlineweight(3);
zsell.hidebubble();

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


# when a buy signal appears,
# look ahead for a sell signal


def n = 200;
def next = if !long_buy then 0
else fold i = 0 to n+1
 with p
 while !getvalue(long_sell, -i)
 do p + 1;

def sell_pr = if !long_buy then 0
 else if next == 0 or next == n then 0
 else getvalue(close, -next);

def cnt = if long_buy and sell_pr > 0 then next
 else if cnt[1] > 1 then cnt[1] - 1 
 else 0;

def slope = if long_buy and sell_pr > 0 then (sell_pr - close)/next
 else if cnt > 0 then slope[1]
 else 0;


# look at prev bar, to draw line up to sell bar
def k = if long_buy then close
 else if cnt[1] > 0 then k[1] + slope[1]
 else na;


plot z = k;
z.SetDefaultColor(Color.cyan);


addchartbubble(0, low,
long_buy + "\n" +
next + "\n" +
cnt + "\n" +
slope + "\n" +
k
, color.yellow, no);

#

ulUAidY.jpg
 

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

Thanks for this, this is fantastic!

Have been working with the code you posted to make an adjustment, because I'm using this on a tick chart so the length of 200 for n isn't necessarily enough.

(For example, in my previous hypothetical, if the RSI was oversold for 250 bars then the line would stop drawing after 202 bars, and another line would not start from bars 203 - 250.)

For the purpose of making the line slope more meaningful in segments that still represent local trend directions, I would rather not increase n to a larger number. Instead I want to start a new line.

I'm having difficulty figuring out why this code isn't working to draw another line if the current line has reached the maximum length allowed with n being set to 200 (which appears to be 202):


Code:
def long_buy_pre = ma1xup;

def n_pre = 200;
def next_pre = if !long_buy_pre then 0
else fold i_pre = 0 to n_pre+1
 with p_pre
 while !getvalue(long_buy_pre, -i_pre)
 do p_pre + 1;

def sell_pr_pre = if !long_buy_pre then 0
 else if next_pre == 0 or next_pre == n_pre then 0
 else getvalue(close, -next_pre);

def cnt_pre = if long_buy_pre and sell_pr_pre > 0 then next_pre
 else if cnt_pre[1] > 1 then cnt_pre[1] - 1
 else 0;

def slope_pre = if long_buy_pre and sell_pr_pre > 0 then (sell_pr_pre - close)/next_pre
 else if cnt_pre > 0 then slope_pre[1]
 else 0;


# look at prev bar, to draw line up to sell bar
def k_pre = if long_buy_pre then close
 else if cnt_pre[1] > 0 then k_pre[1] + slope_pre[1]
 else na;

def line_bar_countback_pre = if isNan(k_pre) then 0 else line_bar_countback_pre[1]+1;

def new_line_start = line_bar_countback_pre[1]==202;

def long_sell = ma1xdwn or new_line_start[0]==1;
def long_buy = ma1xup or new_line_start[1]==1;


# when a buy signal appears,
# look ahead for a sell signal


def n = 200;
def next = if !long_buy then 0
else fold i = 0 to n+1
 with p
 while !getvalue(long_sell, -i)
 do p + 1;

def sell_pr = if !long_buy then 0
 else if next == 0 or next == n then 0
 else getvalue(close, -next);

def cnt = if long_buy and sell_pr > 0 then next
 else if cnt[1] > 1 then cnt[1] - 1
 else 0;


def slope = if long_buy and sell_pr > 0 then (sell_pr - close)/next
 else if cnt > 0 then slope[1]
 else 0;


# look at prev bar, to draw line up to sell bar
def k = if long_buy then close
 else if cnt[1] > 0 then k[1] + slope[1]
 else na;

def line_bar_countback = if isNan(k) then 0 else line_bar_countback[1]+1;

#AddChartBubble(long_buy or long_sell or new_line_start==1,low,line_bar_countback,color.white);

#AddChartBubble(yes,high,line_bar_countback,color.yellow);

plot z = k;
z.SetDefaultColor(Color.cyan);
z.setlineweight(2);
z.setstyle(curve.firm);

##

I've been trying different approaches for a couple of hours and this logic makes sense to me but I must be wrong because as soon as I add the "or" clause to these lines then the chart breaks / can no longer load anything:

Code:
def long_sell = ma1xdwn or new_line_start[0]==1;
def long_buy = ma1xup or new_line_start[1]==1;

You've been so helpful, I'm sorry to ask for further help but I'm stuck at this point. Do you have an idea of why this method isn't working?

I've settled on a compromise of setting n to a length of 500 but plotting a triangle on the line to indicate when its length has reached 200 and 500. I think that it's not necessarily worth the trouble to figure out how to make new lines start after n=200.

The next thing I am working on now is finding a way to keep track of the bar length of each line that plots on the chart for the purpose of then determining the average line length based on that. I'll give this a try today and see how it goes.

EDIT: I got that working just fine.
 
Last edited:
this uses 2 average lines and looks for them crossing, to make test signals for buying and selling.
it draws a cyan line from the close of buy signal to the close of sell signal.


ulUAidY.jpg

I did discover a major problem today unfortunately: lines only plot retroactively to the time the chart is loaded, meaning that if I load the chart at 11am then all lines that should plot before 11am do, but all that should appear after 11am will never plot if I just leave the study and chart up. If I switch the chart to a different ticker, however, and then reload the first ticker chart again from scratch, when the study is loaded then the signals all appear up to the current bar.

I have the arrows removed and am also using this on a tick chart, mentioning that because maybe for some reason that is making a difference. I will keep experimenting but do you have familiarity with this kind of issue, where a study only paints signals that occurred up to the time it was loaded and fails to paint new signals after it was loaded (but re-loading the chart from scratch causes the signals to paint again for all of the bars that it failed to paint)?

It's peculiar because I also confirm that the test bubbles are working at the long_buy and long_sell conditions: but the slope etc. show N/A in the test bubble where the line should have been painted (for example, the long_buy and long_sell here are the cross of the 13 ema above the 48 ema and cross of the 13 ema below the 48 ema, respectively):

Capture-test-1.PNG



If I refresh the chart or reload the study though then the line appears as it should:

Capture-test-2.PNG


(the cloud above the line is something else I am working on but it's unrelated to the logic of the line appearing and I confirmed the problem persists when the study’s original code is run in isolation)
 
Last edited:
Actually I am seeing a major problem now with the study: all the signals that would have completed (with long_buy and long_sell both having been triggered) appear when the chart or study is first loaded, but all additional lines are never drawn for any bars (any time that passes) which appear after the study was first loaded. If I switch the chart to a different ticker, however, and then reload the first ticker chart again from scratch, since the study was loaded again then the signals all appear up to the current bar.

I have the arrows removed and am also using this on a tick chart, mentioning that because maybe for some reason that is making a difference. I will keep experimenting but do you have familiarity with this kind of issue, where a study only paints signals that occurred up to the time it was loaded and fails to paint new signals after it was loaded (but re-loading the chart from scratch causes the signals to paint again for all of the bars that it failed to paint)?

It's peculiar because I also confirm that the test bubbles are working at the long_buy and long_sell conditions: but the slope etc. show N/A in the test bubble where the line should have been painted (for example, the long_buy and long_sell here are the cross of the 13 ema above the 48 ema and cross of the 13 ema below the 48 ema, respectively):

View attachment 18990


If I refresh the chart or reload the study though then the line appears as it should:

View attachment 18991

(the cloud above the line is something else I am working on but it's unrelated to the logic of the line appearing and can't be the reason for the problem)

Do you have any idea how this could be fixed or what is causing it? I don't know why a study would only plot signals retroactively upon being loaded but not keep plotting the subsequent signals that should be appearing after it was loaded earlier.

@halcyonguy Mobius in the ThinkScript TOS chat room said that there is a 500 bar delay in plotting the lines, I believe he said that based on this part (I changed n to 500 from 200):

"
def n = 500;
def next = if !long_buy then 0
else fold i = 0 to n+1
with p
while !getvalue(long_sell, -i)
do p + 1;"

That doesn't make sense to me though because the actual trigger conditions (the MA crossovers) don't refer to future bars and also, if the chart is re-loaded fresh then even a line that should have plotted one bar ago will plot correctly. He offered a trendline script that he wrote but it seems poorly suited to my purpose because I think you'd have to define a new plot for each line that you want drawn. Whereas your code is perfect for my needs, because I only want one plot defined for every line that is drawn based on the same triggers. (One advantage of this for example is that it's easy to calculate the average length of the lines and compare any individual line against the average.)

Whether or not the explanation makes sense, if this is the part of the code that is responsible for the chart needing to be reloaded in order for the line plots to keep updating correctly, then the script is not usable for live trading. Do you have an idea of how this issue could be fixed? I haven't been able to make any progress on it after spending most of today trying to get help from the ThinkScript chat lounge. I can't figure out a way to adapt the Mobius trendline logic to do what I want so I’m hoping that there’s a way to make your code update the chart in realtime without needing to intermittently reload the study.
 
Last edited:
@halcyonguy Mobius in the ThinkScript TOS chat room said that there is a 500 bar delay in plotting the lines, I believe he said that based on this part (I changed n to 500 from 200):

"
def n = 500;
def next = if !long_buy then 0
else fold i = 0 to n+1
with p
while !getvalue(long_sell, -i)
do p + 1;"

That doesn't make sense to me though because the actual trigger conditions (the MA crossovers) don't refer to future bars and also, if the chart is re-loaded fresh then even a line that should have plotted one bar ago will plot correctly. He offered a trendline script that he wrote but it seems poorly suited to my purpose because I think you'd have to define a new plot for each line that you want drawn. Whereas your code is perfect for my needs, because I only want one plot defined for every line that is drawn based on the same triggers. (One advantage of this for example is that it's easy to calculate the average length of the lines and compare any individual line against the average.)

Whether or not the explanation makes sense, if this is the part of the code that is responsible for the chart needing to be reloaded in order for the line plots to keep updating correctly, then the script is not usable for live trading. Do you have an idea of how this issue could be fixed? I haven't been able to make any progress on it after spending most of today trying to get help from the ThinkScript chat lounge. I can't figure out a way to adapt the Mobius trendline logic to do what I want so I’m hoping that there’s a way to make your code update the chart in realtime without needing to intermittently reload the study.

sorry, i don't have an answer now. my code drew lines on a normal chart. i don't use tick charts, so not sure what effect that would have. in a day or 2 , i can experiment with it. i will draw bubbles with many values, to try to learn what is happening.

i don't understand the statement about delays with the fold? on a buy signal, the loop looks at future bars, for a sell signal, and returns the quantity of bars, from buy to sell.
 
sorry, i don't have an answer now. my code drew lines on a normal chart. i don't use tick charts, so not sure what effect that would have. in a day or 2 , i can experiment with it. i will draw bubbles with many values, to try to learn what is happening.

i don't understand the statement about delays with the fold? on a buy signal, the loop looks at future bars, for a sell signal, and returns the quantity of bars, from buy to sell.
edit: this ended up being the issue and solution: https://usethinkscript.com/threads/price-roc-for-line.15921/#post-127625
 
Last edited:
I thought of trying a different approach and logically it should work but it seems to be too complex to run or there's a different problem I don't understand:

I added the following code at the beginning of the script to calculate how many bars back the current candle is from the long_buy condition triggering:

Code:
def FormingBar = !IsNaN(open) and IsNaN(open [-1] ) ;  # This is 1 if true and 0 is false.
def FormingBarNumber = if FormingBar is true then barnumber() else double.nan ;
def long_buy_barnumber = if long_buy is true then barnumber() else long_buy_barnumber[1];
AddLabel(yes,long_buy_barnumber,Color.White);
AddLabel(yes,FormingBarNumber,Color.White);

def n_open_calc = FormingBarNumber-long_buy_barnumber;

AddLabel(yes,n_open_calc,Color.White);

Then I tried setting that value (minus 1, so that it's using the last closed candle) as the length of n. I tried it for "n" and in case it was interfering with being able to start the plot normally from long_buy triggering, I also tried defining "n_b" (and next_b which uses n_b) as that value and making the sell_pr variable use n_b instead of n, like this:

Code:
def n = 200;
def next = if !long_buy then 0
else fold i = 0 to n+1
 with p
 while !getvalue(long_sell, -i)
 do p + 1;

def n_b = n_open_calc-1;
def next_b = if !long_buy then 0
else fold i_b = 0 to n_b+1
 with p_b
 while !getvalue(long_sell, -i_b)
 do p_b + 1;

def sell_pr = if !long_buy then 0
 else if next_b == 0 or next_b == n_b then 0
 else getvalue(close, -next_b);

If for example "n_open_calc" (the number of bars between the current candle and the long_buy trigger) is 35, and I set n_b to 34 directly, then of course the plots appear as normal.

But if I set n_b as "def n_b = n_open_calc-1;" then it can't plot and breaks the script.

It seems like logically this should work while also allowing the added benefit of letting the non-completed lines still plot as lines in progress (i.e. not having to wait for the long_sell condition to trigger to paint the line, and instead having a repainting line appear as the line length is still increasing).

So maybe the issue is that the script is too complex using "n_open_calc-1" as a length of n, or maybe I don't understand how this has broken the logic of the script. My plan had been to have one plot for the completed lines that used curve.firm and a second plot for the in-progress lines that would use curve.short_dash.

However, I am happy to share that I tried the solution from the thread I linked above in the preceding post, and it worked:

Code:
# force repainting in real-time: (barsFwd should be "the offset's length")
def barsFwd = 500;
plot forceBarRepaint = close[-barsFwd] * Double.NaN;

This did solve the problem! Now on a tick chart the lines plot in real time without the script needing to be reloaded to make the lines appear that should have appeared after it was first loaded.
 

Similar threads

Not the exact question you're looking for?

Start a new thread and receive assistance from our community.

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