# PSAR Transition Indicator
# tomsk
# 11.20.2019
# V1.0 - 11.20.2019 - tomsk - Initial release of PSAR Transition Indicator
# This study looks for a PSAR state transition (either from bullish to bearish
# or vice versa) and plots a horizontal price line into the expansion area. If
# the state transition already triggered, it calculates the number of bars ago
# the event happened. I've included labels, alerts as well as chart bubbles
# Update 09/21/22 by powerhousescott
# I have added price lines that you can turn on and off. If working with upper charts you will #have to adjust the aggregation up by a couple of time frames as desired.
# I have added an adjustable candle count and bubbles with win percentage labels
declare upper;
#Price lines will plot a horizontal bar at each close and and Active price line from a larger #time frame as desired.
input ShowPrice = yes;
input ShowPrevClose= yes;
input PriceAgg = AggregationPeriod.THREE_DAYS;
plot PrevClose = if !ShowPrevClose then double.NaN else close;
PrevClose.SetLineWeight(5);
PrevClose.SetDefaultColor(Color.CYAN);
PrevClose.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
plot ActivePriceLine=
if !ShowPrice then Double.NaN else Highest(close(period = AggregationPeriod.TWO_DAYS), 1);
ActivePriceLine.SetLineWeight(5);
ActivePriceLine.SetDefaultColor(Color.White);
ActivePriceLine.SetPaintingStrategy(PaintingStrategy.LINE);
#PSAR Code
input accelerationFactor = 0.02;
input accelerationLimit = 0.2;
Assert(accelerationFactor > 0, "'acceleration factor' must be positive: " + accelerationFactor);
Assert(accelerationLimit >= accelerationFactor, "'acceleration limit' (" + accelerationLimit + ") must be greater than or equal to 'acceleration factor' (" + accelerationFactor + ")");
def bar = BarNumber();
def state = {default init, long, short};
def extreme;
def SAR;
def acc;
switch (state[1])
{
case init:
state = state.long;
acc = accelerationFactor;
extreme = high;
SAR = low;
case short:
if (SAR[1] < high)
then {
state = state.long;
acc = accelerationFactor;
extreme = high;
SAR = extreme[1];
}
else
{
state = state.short;
if (low < extreme[1])
then {
acc = Min(acc[1] + accelerationFactor, accelerationLimit);
extreme = low;
}
else {
acc = acc[1];
extreme = extreme[1];
}
SAR = Max(Max(high, high[1]), SAR[1] + acc * (extreme - SAR[1]));
}
case long:
if (SAR[1] > low)
then {
state = state.short;
acc = accelerationFactor;
extreme = low;
SAR = extreme[1];
}
else
{
state = state.long;
if (high > extreme[1])
then
{
acc = Min(acc[1] + accelerationFactor, accelerationLimit);
extreme = high;
}
else
{
acc = acc[1];
extreme = extreme[1];
}
SAR = Min(Min(low, low[1]), SAR[1] + acc * (extreme - SAR[1]));
}
}
plot parSAR = SAR;
parSAR.SetLineWeight(2);
parSAR.SetPaintingStrategy(PaintingStrategy.POINTS);
parSAR.AssignValueColor(if state == state.short then Color.MAGENTA else Color.GREEN);
plot parsar2 = SAR;
parsar2.SetLineWeight(5);
parsar2.SetPaintingStrategy(PaintingStrategy.SQUARES);
parsar2.SetDefaultColor(Color.WHITE);
def transitionBull = state[1] == state.short and state == state.long;
def transitionBear = state[1] == state.long and state == state.short;
def transitionBar = if transitionBull or transitionBear
then bar
else (transitionBar[1]);
def transitionPrice = if bar == transitionBar
then close
else transitionPrice[1];
def transitionBarsAgo = if bar != transitionBar
then bar - transitionBar
else if bar == transitionBar
then Double.NaN
else transitionBarsAgo[1];
#PSAR Transition Labels
AddLabel(transitionBull or transitionBear, "PSAR Trans Now!!!", Color.YELLOW);
AddLabel(!(transitionBull or transitionBear), "PSAR Trans " + transitionBarsAgo + " bars ago", Color.CYAN);
Alert(transitionBull, "PSAR Transition Bull", Alert.BAR, Sound.Ding);
Alert(transitionBear, "PSAR Transition Bear", Alert.BAR, Sound.Ring);
#Time Axis, Highline, Lowline
def timeAxis = if IsNaN(close[-1]) and !IsNaN(close) then bar else timeAxis[1];
def highline = if transitionBar == Highest(transitionBar)
then transitionPrice
else highline[1];
def lowline = if transitionBar == LowestAll(transitionBar)
then (transitionPrice)
else lowline[1];
#Bull and Highline Plots
def bull = if transitionBull then 1 else if bull[1] == 1 and !transitionBear then 1 else 0;
def Bear = if transitionBear then 1 else if Bear[1] == 1 and !transitionBull then 1 else 0;
plot hLine = highline;
hLine.SetLineWeight(4);
hLine.AssignValueColor(if bull then Color.GREEN else Color.RED);
hLine.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
plot LLine = lowline;
LLine.SetLineWeight(4);
LLine.AssignValueColor(if Bear then Color.RED else Color.CYAN);
LLine.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
#BullHi Plot, Bubbles, Marker
input show_bubbles = yes;
input count_labels = yes;
input markers=yes;
input Candle_Count_1 = 3;
input Candle_Count_2 = 4;
input Candle_Count_3 = 5;
input Pars_Cross = 1;
plot bullHi = close >= hLine and transitionBull [Pars_Cross] ;
bullHi.SetLineWeight (5);
bullHi.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_UP);
bullHi.SetDefaultColor(Color.LIGHT_GREEN);
plot BHmark = if !markers then double.nan else bullHi * 2;
def bullHi1 = bullhi from Candle_Count_1 bars ago and close > close [Candle_Count_1];
AddChartBubble(if !Show_Bubbles then double.NaN else bullHi1, close, Candle_Count_1 , Color.LIGHT_GREEN);
def bullHi2 = bullhi from Candle_Count_2 bars ago and close > close [Candle_Count_2];
AddChartBubble(if !Show_Bubbles then double.Nan else bullHi2, close, Candle_Count_2, Color.LIGHT_GREEN);
def bullHi3 = bullhi from Candle_Count_3 bars ago and close > close [Candle_Count_3] ;;
AddChartBubble(if !Show_Bubbles then double.nan else bullHi3, close, Candle_Count_3, Color.LIGHT_GREEN);
#Bull_high Counts and Labels
def CountBH = if bar == !bullHi then 0 else if bullHi then (CountBH [1] + 1) else CountBH [1];
def CountBH1 = if bar == !bullHi1 then 0 else if bullHi1 then (CountBH1[1] + 1) else CountBH1[1];
def CountBH2 = if bar == !bullHi2 then 0 else if bullHi2 then (CountBH2[1] + 1) else CountBH2[1];
def CountBH3 = if bar + 1 == !bullHi3 then 0 else if bullHi3 then (CountBH3[1] + 1) else CountBH3[1];
AddLabel(count_labels, "PARS Hi Cnt " + CountBH + " [CC " + Candle_Count_1 + "] " + Round(CountBH1 / CountBH * 100, 0) + "%" + " [CC " + Candle_Count_2 + "] " + Round(CountBH2 / CountBH * 100, 0) + "%" + " [CC " + Candle_Count_3 + "] " + Round(CountBH3 / CountBH * 100, 0) + "%", Color.LIGHT_GREEN);
#Bear Low Plot and bubbles
plot BearLo = close <= LLine and transitionBear [PARS_Cross];
BearLo.SetLineWeight (5);
BearLo.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_DOWN);
BearLo.SetDefaultColor(Color.LIGHT_ORANGE);
plot BLoClose = close and BearLo;
BLoClose.SetLineWeight (5);
BLoClose.SetPaintingStrategy(PaintingStrategy.BOOLEAN_WEDGE_DOWN);
BLoClose.SetDefaultColor(Color.LIGHT_ORANGE);
plot BLoMark = if !markers then double.nan else BLoClose * 2;
def BearLo1 = BearLo from Candle_Count_1 bars ago and close < close [Candle_Count_1] ;
AddChartBubble(BearLo1, close, Candle_Count_1, Color.LIGHT_ORANGE);
def BearLo2 = BearLo from Candle_Count_2 bars ago and close < close [Candle_Count_2] ;
AddChartBubble(BearLo2, close, Candle_Count_2, Color.LIGHT_ORANGE);
def BearLo3 = BearLo from Candle_Count_3 bars ago and close < close [Candle_Count_3] ;
AddChartBubble(BearLo3, close, Candle_Count_3, Color.LIGHT_ORANGE);
#Bull_Low Counts and Labels
def CountBL = if bar == !BearLo then 0 else if BearLo then (CountBL[1] + 1) else CountBL[1];
def CountBL1 = if bar == !BearLo1 then 0 else if BearLo1 then (CountBL1[1] + 1) else CountBL1[1];
def CountBL2 = if bar == !BearLo2 then 0 else if BearLo2 then (CountBL2[1] + 1) else CountBL2[1];
def CountBL3 = if bar == !BearLo3 then 0 else if BearLo3 then (CountBL3[1] + 1) else CountBL3[1];
AddLabel(count_labels, "PSAR Lo Cnt " + CountBL + " [CC " + Candle_Count_1 + "] " + Round(CountBL1 / CountBL * 100, 0) + "%" + " [CC " + Candle_Count_2 + "] " + Round(CountBL2 / CountBL * 100, 0) + "%" + " [CC " + Candle_Count_3 + "] " + Round(CountBL3 / CountBL * 100, 0) + "%", Color.LIGHT_ORANGE);
# End PARS Transition Indicator