# predict_crossing_00d
# find if 2 lines will cross in the future, if they were extended.
# halcyonguy 12/2021
def na = double.nan;
def bn = barnumber();
def lastbar = !isnan(close[0]) and isnan(close[-1]);
def lastbarbn = if bn == 1 then na else if lastbar then bn else lastbarbn[1];
# ------------------------------------------------------
# 2 averages for testing
input avg1_len = 9;
input avg1_type = AverageType.simple;
def ma1 = MovingAverage(avg1_type, close, avg1_len);
input avg2_len = 20;
input avg2_type = AverageType.simple;
def ma2 = MovingAverage(avg2_type, close, avg2_len);
plot z1 = ma1;
z1.setdefaultcolor(color.cyan);
plot z2 = ma2;
z2.setdefaultcolor(color.yellow);
addlabel(1, "avg1 len " + avg1_len, color.yellow);
addlabel(1, "avg2 len " + avg2_len, color.yellow);
# ------------------------------------------------------
# set 2 formulas to sig1 and sig2
def sig1 = ma1;
def sig2 = ma2;
# calc close chg from a bar, x bars back
input barsback_for_offest_for_slope = 1;
def bb = barsback_for_offest_for_slope;
def s1chg = if !isnan(close) then (sig1[0] - sig1[bb])/bb else s1chg[1];
def s2chg = if !isnan(close) then (sig2[0] - sig2[bb])/bb else s2chg[1];
#check if 2 signals are moving towards each other , consolidating
def consol1 = if (sig1 > sig2 and s1chg < s2chg) then 1 else 0;
def consol2 = if (sig1 < sig2 and s1chg > s2chg) then 1 else 0;
def consol = (consol1 or consol2);
def notconsol = (!consol1 or !consol2);
def consolcnt = if ( !consol[1] and consol) then 1 else (consolcnt[1] + 1);
def wideningcnt = if ( consol[1] and !consol) then 1 else (wideningcnt[1] + 1);
addlabel(1, "bars back for offest for slope " + bb, color.lime);
addlabel(consol, "consolidating for " + consolcnt + " bars", color.yellow);
addlabel(!consol, "widening for " + wideningcnt + " bars", color.magenta);
# ------------------------------------
# bars till a crossing
def bars_x = round( (sig2 - sig1) / (s1chg - s2chg), 0);
# future price levels
def f1 = round((sig1 + ( bars_x * s1chg)), 2);
def f2 = round((sig2 + ( bars_x * s2chg)), 2);
addlabel(1, "#1 chg: " + s1chg, color.yellow);
addlabel(1, "#2 chg: " + s2chg, color.yellow);
addlabel(consol, "#1 cross $: " + f1, color.cyan);
addlabel(consol, "#2 cross $: " + f2, color.cyan);
#--------------------
def cross_price = if (!isnan(close[-1]) or notconsol) then na
else if lastbar then (sig1 + ( bars_x * s1chg))
else cross_price[1];
plot z4 = cross_price;
z4.SetStyle(Curve.MEDIUM_DASH);
z4.SetDefaultColor(Color.cyan);
z4.setlineweight(1);
z4.hidebubble();
#--------------------
#if last bar then bn of crossing
def bnx = if lastbar then (bars_x + bn) else bnx[1];
addlabel(consol, "last# " + lastbarbn + " cross # " + bnx , color.pink);
# extended lines , after lastbar
def extline_offset = 1;
def ex1 = if bn == 1 then na else
if lastbar[extline_offset] then sig1[extline_offset] + s1chg[extline_offset]
else (ex1[1] + s1chg);
plot ext1 = ex1;
ext1.SetStyle(Curve.MEDIUM_DASH);
ext1.setdefaultcolor(color.white);
#ext1.setlineweight(1);
ext1.hidebubble();
# start on lastbar
#def ex2 = if bn == 1 then na else
# if lastbar then sig2
# else (ex2[1] + s2chg);
# start on a bar after lastbar, so there is a gap between lines
def ex2 = if bn == 1 then na else
if lastbar[extline_offset] then sig2[extline_offset] + s2chg[extline_offset]
else (ex2[1] + s2chg);
plot ext2 = ex2;
ext2.SetStyle(Curve.MEDIUM_DASH);
ext2.setdefaultcolor(color.white);
#ext2.setlineweight(1);
ext2.hidebubble();
# draw vert line at time of lines crossing
addverticalline(bn == bnx , "signal cross", color.yellow);
def bars_xb = round(bars_x,0);
AddLabel(consol, "signals 1 & 2 will cross in " + bars_xb + " bars", Color.YELLOW);
AddLabel(!consol, "signals 1 & 2 will not cross", Color.magenta);
#--------------------------------
# test data
input test1 = no;
addchartbubble( test1, low *0.992, "C " + consolcnt + "\nW " + wideningcnt, color.cyan, no);
input test2 = no;
addchartbubble(test2, cross_price, bn + "\n" + ex1 + "\n" + ex1[1] + "\n" + s1chg , color.cyan, no);
input test3 = no;
addchartbubble(test3, cross_price, bn + "\n" + ex1 + "\n" + ex1[1] + "\n" + s1chg , color.cyan, no);
input test4 = no;
addchartbubble(test4, cross_price, bn + "\n" + bnx + "\n" + 0 , color.cyan, no);
# ==================================
# https://tlc.thinkorswim.com/center/reference/thinkScript/Constants/AverageType
# EXPONENTIAL
# HULL
# SIMPLE
# WEIGHTED
# WILDERS
# ==============================
# derive a formula
# ----------------
# this is the result formula from below
# signal diff is on top and bar to bar changes are on bottom.
# bars_x = (sig2 - sig1) / (s1chg - s2chg)
# ----------------
# if sig1 > sig2 then,
# look for when sig1 < sig2q
#
# (sig1 + ( bars_x * s1chg)) <= (sig2 + ( bars_x * s2chg))
#
# rename vars and simplify
# a=sig1
# b=sig2
# a2=s1chg
# b2=s2chg
# x=bars_x
# (a + ( x * a2)) <= (b + ( x * b2))
# a2*x + a <= b2*x + b
# a2*x - b2*x <= b - a
# (a2 - b2) / x <= b - a
# (a2 - b2) <= (b - a ) * x
# (a2 - b2) / (b - a ) <= x
# replace var names
# invert formula, so signal diff is on top and bar to bar changes are on bottom.
#def bars_x = round( (sig2 - sig1) / (s1chg - s2chg), 1);
#=============================
#