I'm learning ThinkScript with the goal of creating studies that can be used for some more advanced scans. Right now I'm working on two studies, the second of which builds on the first. The first study detects gaps that haven't yet been filled, with some wiggle room thresholds for "close enough" gap fills and for disregarding gaps below a specified size. The outputs are two boolean plots - one for gap ups, and one for gap downs. I had to do some mental and code gymnastics to get it all to work so I hope the code does an ok job of explaining itself. The bottom line is that it seems to work pretty well on individual charts, but it always results in a timeout when it's implemented in a scan. Basically I just put the default study parameters in with a 10-day scan window, checking if gapup_unfilled_plot == 1.
My hope is that I've made some sloppy mistake that prevents the code from ever actually completing, but I don't have the experience or knowledge yet to be able to see it myself, so I was hoping I could get some help here. If you decide to run the code, it's best displayed on a lower chart window/subplot.
If you wish to test this code, GLD is a ticker with a lot of gaps and can be run with default settings to see exactly what this script does. I appreciate any help I can get! The gap fill line o f code (bool_gapup_filled) is my biggest suspect for the problem, I just don't know how it can be improved. Also, even though it's inefficient, I wouldn't expect the scan to completely time out with this line unless there is a hard-coded time limit for how long the script can be run in total - it appears to run in about a second when I put it on a chart.
My hope is that I've made some sloppy mistake that prevents the code from ever actually completing, but I don't have the experience or knowledge yet to be able to see it myself, so I was hoping I could get some help here. If you decide to run the code, it's best displayed on a lower chart window/subplot.
Code:
input search_length = 200; # The number of bars forward to check for gap fills for each gap detected
input atr_length = 50; # The length to use for the ATR indicator, which is used for thresholding
input ATR_min_gap_thresh = 1.0; # 0-20, number of ATRs required for a gap to be detected
input ATR_fill_thresh = 0.05; #Number of ATRs short of a gap fill allowed for a gap to be considered filled
declare once_per_bar;
def ATR_line = reference ATR(atr_length);
def ATR_gap_line = ATR_line * ATR_min_gap_thresh;
def ATR_fill_line = ATR_line * ATR_fill_thresh;
#def ATR_movement_line = ATR_line * gap_movement_thresh;
#def ATR_close_alert_line = ATR_line * gap_alert_thresh;
#Right-shifted price history
#def r_open = open[1];
#def r_high = high[1];
#def r_low = low[1];
def r_close = close[1];
#Step 1 - create gap level lines
#Gap ups
def v_gapup = CompoundValue(1, if (open - r_close) > ATR_gap_line then (r_close) else v_gapup[1], 0); #Line that moves to bottom of gap up each time one is detected
def bool_gapup = if (open - r_close) > ATR_gap_line and low > r_close then 1 else 0; #Boolean sequence that is set to 1 for the second bar of each gap that is detected.
#Gap downs - repeat of gap ups with logic for gap down
def v_gapdn = CompoundValue(1, if (r_close - open) > ATR_gap_line then (r_close) else v_gapdn[1], 0);
def bool_gapdn = if (r_close - open) > ATR_gap_line and high < r_close then 1 else 0;
#Step 2 - filter out filled gaps
#Gap ups
def bool_gapup_filled = fold i = -search_length to 0 with A = 0 do A or if !IsNaN(low[i]) then ((bool_gapup and (low[i]-ATR_fill_line[i]) <= v_gapup)) else 0; #The goal is: for each bar where a gap is detected, scan forward up to the last bar recorded to see if the gap has been filled. This actually checks every single bar against search_length other bars, which makes it extremely inefficient. If the search could only take place on bars where a gap is detected, and could stop at the latest bar, it would be sped up considerably.
#Gap downs
def bool_gapdn_filled = fold ii = -search_length to 0 with AA = 0 do AA or if !IsNaN(high[ii]) then ((bool_gapdn and (v_gapdn-ATR_fill_line[ii]) <= high[ii])) else 0;
def bool_gapup_unfilled = (bool_gapup and !bool_gapup_filled); #Crosses gaps filled with gaps detected to get gaps unfilled
def bool_gapdn_unfilled = (bool_gapdn and !bool_gapdn_filled);
#def bool_gap_unfilled = (bool_gapup and !bool_gapup_filled) or (bool_gapdn and !bool_gapdn_filled);
plot gapup_unfilled_plot = bool_gapup_unfilled;
gapup_unfilled_plot.SetDefaultColor(Color.GREEN);
gapup_unfilled_plot.SetPaintingStrategy(PaintingStrategy.HISTOGRAM);
plot gapdn_unfilled_plot = bool_gapdn_unfilled;
gapdn_unfilled_plot.SetDefaultColor(Color.RED);
gapdn_unfilled_plot.SetPaintingStrategy(PaintingStrategy.HISTOGRAM);
#plot gapup_unfilled_plot = bool_gap_unfilled;
#gapup_unfilled_plot.SetDefaultColor(Color.WHITE);
#gapup_unfilled_plot.SetPaintingStrategy(PaintingStrategy.HISTOGRAM);
If you wish to test this code, GLD is a ticker with a lot of gaps and can be run with default settings to see exactly what this script does. I appreciate any help I can get! The gap fill line o f code (bool_gapup_filled) is my biggest suspect for the problem, I just don't know how it can be improved. Also, even though it's inefficient, I wouldn't expect the scan to completely time out with this line unless there is a hard-coded time limit for how long the script can be run in total - it appears to run in about a second when I put it on a chart.