# Parabolic_SAR_Moving_Average_Trading_Strategy
# ParabolicSAR_Trendy_Strategy_1_18
# by BabyTrader using the following article: Parabolic SAR Moving Average Trading Strategy
# https://tradingstrategyguides.com/parabolic-sar-moving-average-trade-strategy/
# ParabolicSAR_withAlerts_JQ
# 2018-04-15 Mods by Johnny Quotron
# with a very helpful kickstart from DMonkey
# Mods include
# 1. splitting the PSAR into two visible plots so that they can be colored seperately
# 2. adding alert arrows at the PSAR to enhance visibility
# a. original alert arrows remain available but are hidden by default
# 3. add ability to color color alert arrows
#
# Combined/Modified/Altered by SilverWolf
declare upper;
#======== Inputs ==============================================================================
input TradeSize = 1;
input SarBars = 1;
input accelerationFactor = 0.012;
input accelerationLimit = 0.2;
input extremeoffset = 0.0;
input MovAvgType = AverageType.EXPONENTIAL;
input MovAvgTrendMethod = {default "SINGLE", "CROSSING"};
input CrossingAvgLength = 9;
input TrendTriggerAvgLength = 21;
input TradeClosingMethod = {default "SAR", "MOVAVG"};
def Trend = if MovAvgTrendMethod == MovAvgTrendMethod."SINGLE" then 1 else
if MovAvgTrendMethod == MovAvgTrendMethod."CROSSING" then 2 else 0;
def PlotCross = if Trend == 2 then yes else no;
def Closer = if TradeClosingMethod == TradeClosingMethod."SAR" then 1 else
if TradeClosingMethod == TradeClosingMethod."MOVAVG" then 2 else 0;
#======== Moving Averages ======================================================================
plot TriggerAVG = MovingAverage(MovAvgType, close, TrendTriggerAvgLength);
TriggerAVG.SetLineWeight(3);
TriggerAVG.SetDefaultColor(Color.WHITE);
plot CrossingAVG = MovingAverage(MovAvgType, close, CrossingAvgLength);
CrossingAVG.SetHiding(!PlotCross);
CrossingAVG.SetLineWeight(3);
CrossingAVG.SetDefaultColor(Color.PINK);
#======== ParabolicSAR =========================================================================
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 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 + extremeoffset;
SAR = extreme[1];
} else {
state = state.short;
if (low < extreme[1])
then {
acc = Min(acc[1] + accelerationFactor, accelerationLimit);
extreme = low - extremeoffset;
} 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 - extremeoffset;
SAR = extreme[1];
} else {
state = state.long;
if (high > extreme[1])
then {
acc = Min(acc[1] + accelerationFactor, accelerationLimit);
extreme = high + extremeoffset;
} else {
acc = acc[1];
extreme = extreme[1];
}
SAR = Min(Min(low, low[1]), SAR[1] + acc * (extreme - SAR[1]));
}
}
#======== ADX ===========================================================================
input ADXlength = 14;
input averageType = AverageType.WILDERS;
input mom = 20;
def hiDiff = high - high[1];
def loDiff = low[1] - low;
def plusDM = if hiDiff > loDiff and hiDiff > 0 then hiDiff else 0;
def minusDM = if loDiff > hiDiff and loDiff > 0 then loDiff else 0;
def ATR = MovingAverage(averageType, TrueRange(high, close, low), ADXlength);
def "DI+" = 100 * MovingAverage(averageType, plusDM, ADXlength) / ATR;
def "DI-" = 100 * MovingAverage(averageType, minusDM, ADXlength) / ATR;
def DX = if ("DI+" + "DI-" > 0) then 100 * AbsValue("DI+" - "DI-") / ("DI+" + "DI-") else 0;
def ADX = MovingAverage(averageType, DX, ADXlength);
#======== Logic =========================================================================
input adxLogic = yes;
def Logic = if adxLogic and ADX > mom
then 1
else if adxLogic and ADX < mom
then 2
else if !adxLogic
then 1
else Double.NaN;
#======== SIGNALS =========================================================================
def BuySignal = if Logic == 1 and Trend == 1 and (close > TriggerAVG ) and (SAR crosses below close)
then 1
else if Logic == 1 and Trend == 2 and (close > TriggerAVG) and (CrossingAVG > TriggerAVG) and (SAR crosses below close)
then 1
else if Logic == 2 and Trend == 1 and (close < TriggerAVG ) and (SAR crosses above close)
then 1
else if Logic == 2 and Trend == 2 and (close < TriggerAVG) and (CrossingAVG < TriggerAVG) and (SAR crosses above close)
then 1
else Double.NaN;
def SellSignal = if Logic == 1 and Trend == 1 and (close < TriggerAVG ) and (SAR crosses above close)
then 1
else if Logic == 1 and Trend == 2 and (close < TriggerAVG) and (CrossingAVG < TriggerAVG) and (SAR crosses above close)
then 1
else if Logic == 2 and Trend == 1 and (close > TriggerAVG ) and (SAR crosses below close)
then 1
else if Logic == 2 and Trend == 2 and (close > TriggerAVG) and (CrossingAVG > TriggerAVG) and (SAR crosses below close)
then 1
else Double.NaN;
def BuyExit = if Logic == 1 and Closer == 1 and (close crosses below SAR)
then 1
else if Logic == 1 and Closer == 2 and (close crosses below TriggerAVG)
then 1
else if Logic == 2 and Closer == 1 and (close crosses above SAR)
then 1
else if Logic == 2 and Closer == 2 and (close crosses above TriggerAVG)
then 1
else if Logic == 1 and Closer == 1 and (adx crosses mom)
then 1
else if Logic == 1 and Closer == 2 and (adx crosses mom)
then 1
else if Logic == 2 and Closer == 1 and (adx crosses mom)
then 1
else if Logic == 2 and Closer == 2 and (adx crosses mom)
then 1
else Double.NaN;
def SellExit = if Logic == 1 and Closer == 1 and (close crosses above SAR)
then 1
else if Logic == 1 and Closer == 2 and (close crosses above TriggerAVG)
then 1
else if Logic == 2 and Closer == 1 and (close crosses below SAR)
then 1
else if Logic == 2 and Closer == 2 and (close crosses below TriggerAVG)
then 1
else if Logic == 1 and Closer == 1 and (adx crosses mom)
then 1
else if Logic == 1 and Closer == 2 and (adx crosses mom)
then 1
else if Logic == 2 and Closer == 1 and (adx crosses mom)
then 1
else if Logic == 2 and Closer == 2 and (adx crosses mom)
then 1
else Double.NaN;
#======== STRATEGY ORDERS ===================================================================
def VolStrength = Lg(volume[1]) - Lg(SimpleMovingAvg(volume[1], 2000));
def HighPrice = high;
def LowPrice = low;
AddOrder(OrderType.BUY_TO_OPEN, BuySignal, open[-1], TradeSize, Color.GREEN, Color.GREEN, name = "Long L" + Logic + " T" + Trend);
AddOrder(OrderType.SELL_TO_CLOSE, BuyExit, open[-1], TradeSize, Color.RED, Color.RED, name = "Close L" + Logic + " C" + Closer);
AddOrder(OrderType.SELL_TO_OPEN, SellSignal, open[-1], TradeSize, Color.ORANGE, Color.ORANGE, name = "Short L" + Logic + " T" + Trend);
AddOrder(OrderType.BUY_TO_CLOSE, SellExit, open[-1], TradeSize, Color.WHITE, Color.WHITE, name = "Close L" + Logic + " C" + Closer);
#======== PLOTS ============================================================================
plot BullPSAR = if SAR < close then SAR else Double.NaN;
BullPSAR.SetPaintingStrategy(PaintingStrategy.POINTS);
BullPSAR.SetDefaultColor(Color.LIME);
plot BearPSAR = if SAR > close then SAR else Double.NaN;
BearPSAR.SetPaintingStrategy(PaintingStrategy.POINTS);
BearPSAR.SetDefaultColor(Color.PINK);
#---
def BullSignalAtCandle = Crosses(SAR, close, CrossingDirection.BELOW);
plot BullSignalAtPSAR = if close crosses above SAR
then SAR
else Double.NaN;
BullSignalAtPSAR.SetLineWeight(1);
BullSignalAtPSAR.SetPaintingStrategy(PaintingStrategy.ARROW_UP);
BullSignalAtPSAR.SetDefaultColor(Color.LIME);
def BearSignalAtCandle = Crosses(SAR, close, CrossingDirection.ABOVE);
plot BearSignalAtPSAR = if close crosses below SAR
then SAR
else Double.NaN;
BearSignalAtPSAR.SetLineWeight(1);
BearSignalAtPSAR.SetPaintingStrategy(PaintingStrategy.ARROW_DOWN);
BearSignalAtPSAR.SetDefaultColor(Color.PINK);
#---
plot LongEntrySignal = if BuySignal then BuySignal else Double.NaN;
LongEntrySignal.SetDefaultColor(Color.UPTICK);
LongEntrySignal.SetLineWeight(5);
LongEntrySignal.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_UP);
plot ShortEntrySignal = if SellSignal then SellSignal else Double.NaN;
ShortEntrySignal.SetDefaultColor(Color.DOWNTICK);
ShortEntrySignal.SetLineWeight(5);
ShortEntrySignal.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_DOWN);
plot LongExitSignal = if BuyExit then BuyExit else Double.NaN;
LongExitSignal.SetDefaultColor(Color.WHITE);
LongExitSignal.SetLineWeight(1);
LongExitSignal.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_DOWN);
plot ShortExitSignal = if SellExit then SellExit else Double.NaN;
ShortExitSignal.SetDefaultColor(Color.WHITE);
ShortExitSignal.SetLineWeight(1);
ShortExitSignal.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_UP);
#======== ALERTS ===========================================================================
input AlertsOn = No;
Alert(AlertsOn and BullSignalAtCandle, "Bullish PSAR", Alert.BAR, Sound.Ring);
Alert(AlertsOn and BearSignalAtCandle, "Bearish PSAR", Alert.BAR, Sound.Ring);
Alert(AlertsOn and BuySignal, "Bullish PSAR above AVG", Alert.BAR, Sound.Ring);
Alert(AlertsOn and SellSignal, "Bullish PSAR below AVG", Alert.BAR, Sound.Ring);
#======== Paint Bars =======================================================================
input paintBars = No;
AssignPriceColor(if !paintBars
then Color.CURRENT
else if SAR < close
then Color.GREEN
else if SAR > close
then Color.RED
else Color.CURRENT);
#======== Labels ===========================================================================
#Spacer
input blink = no;
input AdvLabelsOn = no;
input simpleLabels = no;
def NewBar = if close[1] != close[2] or high[1] != high[2] or low[1] != low[2] then yes else Double.NaN;
def Clock = if !IsNaN(NewBar) and Clock[1] == 1 then 0 else if !IsNaN(NewBar) and Clock[1] == 0 then 1 else Clock[1];
AddLabel(blink and AdvLabelsOn or SimpleLabels, " ParabolicSAR Strategy Version 01.11 ", if Clock == 0 then Color.WHITE else Color.YELLOW);
AddLabel(!blink and AdvLabelsOn or SimpleLabels, " ParabolicSAR Strategy Version 01.11 ", Color.WHITE);
#Buy
AddLabel(AdvLabelsOn,
if Logic == 1 and Trend == 1 and (close > TriggerAVG ) and (SAR crosses below close) within SarBars bars
or Logic == 1 and Trend == 2 and (close > TriggerAVG) and (CrossingAVG > TriggerAVG) and (SAR crosses below close) within SarBars bars
or Logic == 2 and Trend == 1 and (close < TriggerAVG) and (SAR crosses above close) within SarBars bars
or Logic == 2 and Trend == 2 and (close < TriggerAVG) and (CrossingAVG < TriggerAVG) and (SAR crosses above close) within SarBars bars then " " else " ",
if Logic == 1 and Trend == 1 and (close > TriggerAVG) and (SAR crosses below close) within SarBars bars
or Logic == 1 and Trend == 2 and (close > TriggerAVG) and (CrossingAVG > TriggerAVG) and (SAR crosses below close) within SarBars bars
or Logic == 2 and Trend == 1 and (close < TriggerAVG) and (SAR crosses above close) within SarBars bars
or Logic == 2 and Trend == 2 and (close < TriggerAVG) and (CrossingAVG < TriggerAVG) and (SAR crosses above close) within SarBars bars then Color.GREEN else Color.WHITE);
#BuyClose
AddLabel(AdvLabelsOn,
if Logic == 1 and Closer == 1 and (SAR > close) within SarBars bars
or Logic == 1 and Closer == 2 and (close < TriggerAVG) within SarBars bars
or Logic == 2 and Closer == 1 and (SAR < close) within SarBars bars
or Logic == 2 and Closer == 2 and (close > TriggerAVG)
or Logic == 1 and Closer == 1 and (adx crosses above mom) within SarBars bars
or Logic == 1 and Closer == 2 and (adx crosses above mom) within SarBars bars
or Logic == 2 and Closer == 1 and (adx crosses below mom) within SarBars bars
or Logic == 2 and Closer == 2 and (adx crosses below mom) within SarBars bars then " " else " ",
if Logic == 1 and Closer == 1 and (SAR > close) within SarBars bars
or Logic == 1 and Closer == 2 and (close < TriggerAVG) within SarBars bars
or Logic == 2 and Closer == 1 and (SAR < close) within SarBars bars
or Logic == 2 and Closer == 2 and (close > TriggerAVG)
or Logic == 1 and Closer == 1 and (adx crosses above mom) within SarBars bars
or Logic == 1 and Closer == 2 and (adx crosses above mom) within SarBars bars
or Logic == 2 and Closer == 1 and (adx crosses below mom) within SarBars bars
or Logic == 2 and Closer == 2 and (adx crosses below mom) within SarBars bars then Color.MAGENTA else Color.WHITE);
#Sell
AddLabel(AdvLabelsOn,
if Logic == 1 and Trend == 1 and (close < TriggerAVG) and (SAR crosses above close) within SarBars bars
or Logic == 1 and Trend == 2 and (close < TriggerAVG) and (CrossingAVG < TriggerAVG) and (SAR crosses above close) within SarBars bars
or Logic == 2 and Trend == 1 and (close > TriggerAVG) and (SAR crosses below close) within SarBars bars
or Logic == 2 and Trend == 2 and (close > TriggerAVG) and (CrossingAVG > TriggerAVG) and (SAR crosses below close) within SarBars bars then " " else " ",
if Logic == 1 and Trend == 1 and (close < TriggerAVG) and (SAR crosses above close) within SarBars bars
or Logic == 1 and Trend == 2 and (close < TriggerAVG) and (CrossingAVG < TriggerAVG) and (SAR crosses above close) within SarBars bars
or Logic == 2 and Trend == 1 and (close > TriggerAVG) and (SAR crosses below close) within SarBars bars
or Logic == 2 and Trend == 2 and (close > TriggerAVG) and (CrossingAVG > TriggerAVG) and (SAR crosses below close) within SarBars bars then Color.RED else Color.WHITE);
#SellClose
AddLabel(AdvLabelsOn,
if Logic == 1 and Closer == 1 and (SAR < close) within SarBars bars
or Logic == 1 and Closer == 2 and (close > TriggerAVG) within SarBars bars
or Logic == 2 and Closer == 1 and (SAR > close) within SarBars bars
or Logic == 2 and Closer == 2 and (close < TriggerAVG)
or Logic == 1 and Closer == 1 and (adx crosses below mom) within SarBars bars
or Logic == 1 and Closer == 2 and (adx crosses below mom) within SarBars bars
or Logic == 2 and Closer == 1 and (adx crosses above mom) within SarBars bars
or Logic == 2 and Closer == 2 and (adx crosses above mom) within SarBars bars then " " else " ",
if Logic == 1 and Closer == 1 and (SAR < close) within SarBars bars
or Logic == 1 and Closer == 2 and (close > TriggerAVG) within SarBars bars
or Logic == 2 and Closer == 1 and (SAR> close) within SarBars bars
or Logic == 2 and Closer == 2 and (close < TriggerAVG)
or Logic == 1 and Closer == 1 and (adx crosses below mom) within SarBars bars
or Logic == 1 and Closer == 2 and (adx crosses below mom) within SarBars bars
or Logic == 2 and Closer == 1 and (adx crosses above mom) within SarBars bars
or Logic == 2 and Closer == 2 and (adx crosses above mom) within SarBars bars then Color.LIGHT_GREEN else Color.WHITE);
AddLabel (simpleLabels, if BuySignal within SarBars bars then " " else " ", if BuySignal >= 1 within SarBars bars then Color.GREEN else Color.WHITE);
AddLabel (simpleLabels, if BuyExit within SarBars bars then " " else " ", if BuyExit >= 1 within SarBars bars then Color.MAGENTA else Color.WHITE);
AddLabel (simpleLabels, if SellSignal within SarBars bars then " " else " ", if SellSignal >= 1 within SarBars bars then Color.RED else Color.WHITE);
AddLabel (simpleLabels, if SellExit within SarBars bars then " " else " ", if SellExit >= 1 within SarBars bars then Color.LIGHT_GREEN else Color.WHITE);
AddLabel (AdvLabelsOn or simpleLabels,
if Logic == 2 then " Modified Logic " else " Normal Logic ", Color.WHITE);
#======== EOF =========================================================================