# congestion_box_00d
# add risk/reward lines , 3x
# https://usethinkscript.com/threads/congestion-zone.10503/#post-97560
# post 18
def na = double.nan;
def bn = barnumber();
#-------------------------------------
# choose wick or body price levels
input candle_levels = { default "wick" , "body" };
def highx;
def lowx;
switch (candle_levels) {
case "wick":
highx = high;
lowx = low;
case "body":
highx = max(open, close);
lowx = min(open, close);
}
def ht = highx - lowx;
#-----------------------------------
input min_inside_bars = 3;
input show_label__candle_levels = no;
addlabel(show_label__candle_levels, "Candle levels - " + candle_levels, color.yellow);
input show_label__min_inside_bars = no;
addlabel(show_label__min_inside_bars, "Min inside bars - " + min_inside_bars, color.yellow);
# --------------------------------
# test if a giant candle appears, then ignore it
input ignore_big_candles = no;
input candle_ht_avg_multiplier_max = 5.0;
input candle_height_avg_len = 20;
def ht_avg = round(Average( ht[1], candle_height_avg_len),2);
def ht_avg_factor = round(ht / ht_avg, 1);
def ht_en = !ignore_big_candles or (ht < (ht_avg * candle_ht_avg_multiplier_max));
#----------------------------------
# inside bar , count smaller bars after the current bar
def max_bars = 70;
def future_bar_count = fold k = 1 to max_bars
with q = 1
## congestion , 1 bar parameter within high/low
while (ht_en and (between(getvalue(highx, -k), lowx, highx) or between(getvalue(lowx, -k), lowx, highx)))
## insidebars , top and bottom of bar is within high/low
# while (ht_en and highx[0] >= getvalue(highx, -k) and lowx[0] <= getvalue(lowx, -k))
do q + 1;
# -------------------------------
# count down from mother bar, to last inside bar
def rev_cnt =
if bn == 1 then 0
else if rev_cnt[1] > 1 then (rev_cnt[1] - 1)
else if future_bar_count >= min_inside_bars then future_bar_count
else 0;
def inside_start = (rev_cnt[1] <= 1 and future_bar_count >= min_inside_bars);
def start_cnt = if bn == 1 then 0 else if inside_start then (start_cnt[1] + 1) else start_cnt[1];
#def vert = 0.0006;
def vert = 0.00;
input show_cloud = yes;
input show_bubble_pattern_bar_count = no;
addchartbubble(show_bubble_pattern_bar_count and inside_start, (high * (1 + vert)), future_bar_count, color.gray, yes);
# ----------------------------------
# ----------------------------------
# plot lines
def inside_hi =
if rev_cnt == 0 then na
else if inside_start then highx
else inside_hi[1];
def inside_lo =
if rev_cnt == 0 then na
else if inside_start then lowx
else inside_lo[1];
plot zhi = inside_hi;
plot zlo = inside_lo;
zhi.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
#zhi.SetStyle(Curve.MEDIUM_DASH);
#zhi.SetDefaultColor(Color.cyan);
zhi.SetDefaultColor(Color.gray);
zhi.setlineweight(1);
zhi.hidebubble();
zlo.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
#zlo.SetStyle(Curve.MEDIUM_DASH);
#zlo.SetDefaultColor(Color.cyan);
zlo.SetDefaultColor(Color.gray);
zlo.setlineweight(1);
zlo.hidebubble();
# ---------------------------------------
# use 2 clouds, to avoid 2 adjacent patterns being connected
def iscnt_odd = ( start_cnt % 2 == 1 );
def zhiodd = if (show_cloud and iscnt_odd) then zhi else na;
addcloud(zhiodd, zlo, color.gray);
def zhieven = if (show_cloud and !iscnt_odd) then zhi else na;
addcloud(zhieven, zlo, color.gray);
# ---------------------------------------
input show_arrow_on_bar1 = no;
plot z1 = if show_arrow_on_bar1 and inside_start then (low * (1 - vert)) else na;
z1.SetPaintingStrategy(PaintingStrategy.ARROW_UP);
z1.SetDefaultColor(Color.cyan);
z1.setlineweight(2);
z1.hidebubble();
#
# ---------------------------------
# show risk/reward lines, a multiple of mother bar height
def rng = inside_hi - inside_lo;
input show_risk_reward_lines = yes;
def srr = show_risk_reward_lines;
plot reward1 = if srr then (inside_hi + (1 * rng)) else na;
reward1.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
reward1.SetDefaultColor(Color.gray);
reward1.hidebubble();
plot reward2 = if srr then (inside_hi + (2 * rng)) else na;
reward2.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
reward2.SetDefaultColor(Color.gray);
reward2.hidebubble();
plot reward3 = if srr then (inside_hi + (3 * rng)) else na;
reward3.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
reward3.SetDefaultColor(Color.gray);
reward3.hidebubble();
plot risk1 = if srr then (inside_lo - (1 * rng)) else na;
risk1.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
risk1.SetDefaultColor(Color.gray);
risk1.hidebubble();
plot risk2 = if srr then (inside_lo - (2 * rng)) else na;
risk2.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
risk2.SetDefaultColor(Color.gray);
risk2.hidebubble();
plot risk3 = if srr then (inside_lo - (3 * rng)) else na;
risk3.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
risk3.SetDefaultColor(Color.gray);
risk3.hidebubble();
# ---------------------------------
# add horz lines at,
# highest hi above box,
# and lowest low below box
# iscnt_odd
input show_range_highest_lowest_lines = no;
def srl = show_range_highest_lowest_lines;
def toplimit;
if srl and inside_start then {
toplimit = fold t1 = 0 to max_bars
with top1
while t1 < future_bar_count
do max(top1, getvalue(high, -t1));
} else if srl and rev_cnt > 0 then {
toplimit = toplimit[1];
} else {
toplimit = na;
}
plot zt = toplimit;
zt.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
zt.SetDefaultColor(Color.yellow);
#zt.setlineweight(1);
zt.hidebubble();
def botlimit;
if srl and inside_start then {
botlimit = fold b1 = 0 to max_bars
with bot1 = 999999
while b1 < future_bar_count
do min(bot1, getvalue(low, -b1));
} else if srl and rev_cnt > 0 then {
botlimit = botlimit[1];
} else {
botlimit = na;
}
plot zb = botlimit;
zb.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
zb.SetDefaultColor(Color.yellow);
#zb.setlineweight(1);
zb.hidebubble();
# -----------------------------------
# -----------------------------------
# test stuff - and me
addchartbubble(0, low*0.996,
inside_start + "\n" +
toplimit + "\n" +
rev_cnt + "\n" +
high + "\n"
, ( if inside_start then color.yellow else color.gray), no);
def u = 0;
addchartbubble(u and inside_start, low,
start_cnt + " cnt\n" +
iscnt_odd + " odd"
, color.yellow, no);
# count how many patterns on chart
# if a stock has many, more opportuneties to catch a move
def cnt3 = if bn == 1 then 0 else if (inside_start and future_bar_count == 3) then (cnt3[1] + 1) else cnt3[1];
def cnt4 = if bn == 1 then 0 else if (inside_start and future_bar_count == 4) then (cnt4[1] + 1) else cnt4[1];
def cnt5 = if bn == 1 then 0 else if (inside_start and future_bar_count == 5) then (cnt5[1] + 1) else cnt5[1];
def cnt6 = if bn == 1 then 0 else if (inside_start and future_bar_count == 6) then (cnt6[1] + 1) else cnt6[1];
def cnt7 = if bn == 1 then 0 else if (inside_start and future_bar_count == 7) then (cnt7[1] + 1) else cnt7[1];
def cnt8 = if bn == 1 then 0 else if (inside_start and future_bar_count == 8) then (cnt8[1] + 1) else cnt8[1];
def cnt9 = if bn == 1 then 0 else if (inside_start and future_bar_count == 9) then (cnt9[1] + 1) else cnt9[1];
def cnt10 = if bn == 1 then 0 else if (inside_start and future_bar_count > 9) then (cnt10[1] + 1) else cnt10[1];
input cnt_labels = yes;
addlabel(cnt_labels, " " , color.black);
addlabel(cnt_labels, "3 bars " + cnt3, color.yellow);
addlabel(cnt_labels, "4 bars " + cnt4, color.yellow);
addlabel(cnt_labels, "5 bars " + cnt5, color.yellow);
addlabel(cnt_labels, "6 bars " + cnt6, color.yellow);
addlabel(cnt_labels, "7 bars " + cnt7, color.yellow);
addlabel(cnt_labels, "8 bars " + cnt8, color.yellow);
addlabel(cnt_labels, "9 bars " + cnt9, color.yellow);
addlabel(cnt_labels, "10+ bars " + cnt10, color.yellow);
#