#price_spike_pullback
#https://usethinkscript.com/threads/price-spike-10-bars-ago-then-pullback-to-50ema.18744/#post-142263
#Price spike 10 bars ago then pullback to 50EMA
def na = Double.NaN;
def bn = BarNumber();
#-------------------------------
#A price surge of 30% or higher
# occurred 10 bars ago. ?
# within 20 bars
#input surge_percent = 30.0;
#input surge_percent = 20.0;
input surge_percent = 17.0;
input surge_max_bars = 20;
# find bar #'s of high and low. low has to be first
def minlooff = GetMinValueOffset(low, surge_max_bars);
def maxhioff = GetMaxValueOffset(high, surge_max_bars);
def hi;
def lo;
def surge;
def surgeper;
if bn == 1 then {
hi = 0;
lo = 0;
surge = 0;
surgeper = 0;
} else if (maxhioff < minlooff) then {
# max rise
hi = getvalue(high,maxhioff);
lo = getvalue(low,minlooff);
surge = round(hi - lo,2);
surgeper = round(100*surge/lo,1);
} else {
hi = 0;
lo = 0;
surge = 0;
surgeper = 0;
}
def issurge = surgeper >= surge_percent;
addchartbubble(0, low,
maxhioff + "\n" +
minlooff + "\n" +
hi + " H\n" +
lo + " L\n" +
surge + " S\n" +
surgeper + " %\n"
, (if surge > 0 then color.yellow else color.gray), no);
#-------------------------------
#EMAs (20, 50, 200) are stacked in a bullish manner
def data = close;
input avg1_type = AverageType.exponential;
#input avg1_type = AverageType.Simple;
input avg1_length = 20;
def avg1 = MovingAverage(avg1_type, data, avg1_length );
input avg2_type = AverageType.exponential;
input avg2_length = 50;
def avg2 = MovingAverage(avg2_type, data, avg2_length );
input avg3_type = AverageType.exponential;
input avg3_length = 200;
def avg3 = MovingAverage(avg3_type, data, avg3_length );
input show_average_lines = yes;
plot zavg1 = if show_average_lines then avg1 else na;
plot zavg2 = if show_average_lines then avg2 else na;
plot zavg3 = if show_average_lines then avg3 else na;
zavg1.SetDefaultColor(Color.cyan);
zavg1.setlineweight(1);
zavg1.hidebubble();
zavg2.SetDefaultColor(Color.yellow);
zavg2.setlineweight(1);
zavg2.hidebubble();
zavg3.SetDefaultColor(Color.magenta);
zavg3.setlineweight(1);
zavg3.hidebubble();
def xup = avg1 crosses above avg2;
def xdwn = avg1 crosses below avg2;
def stackup = avg1 > avg2 and avg2 > avg3;
def stackdwn = avg1 < avg2 and avg2 < avg3;
#-------------------------------
# check if all 3 avgs are rising
#-------------------------------
#Price pulled back to 50 EMAs within a margin of 1% or less
#input retrace_near_per = 1.0;
input retrace_near_per = 3.0;
def avgnear = close - avg2;
def avgnearper = round(100*avgnear/avg2,1);
def retrace = avgnearper <= retrace_near_per;
#-------------------------------
#-------------------------------
def maxseq = 2;
def seq = if bn == 1 then 0
else if seq[1] == 2 then 0
else if seq[1] == 0 and issurge and stackup then 1
#else if seq[1] == 1 and stackup then 2
else if seq[1] == 1 and retrace then 2
else seq[1];
def y = 0.007;
plot zup1 = if seq == 1 and seq[1] == 0 then high*(1+y) else na;
zup1.SetPaintingStrategy(PaintingStrategy.points);
zup1.SetDefaultColor(Color.yellow);
zup1.setlineweight(3);
zup1.hidebubble();
plot zup2 = if seq == maxseq then avg2 else na;
zup2.SetPaintingStrategy(PaintingStrategy.ARROW_UP);
zup2.SetDefaultColor(Color.cyan);
zup2.setlineweight(3);
zup2.hidebubble();
addchartbubble((seq == 1 and seq[1] == 0), (low*(1-y)),
"Surge\n" +
surge + "\n" +
surgeper + " %\n"
, color.yellow, no);
#-----------------------------
# scan plot
#plot z = seq == maxseq;
#