ParabolicSAR - PSAR Moving Average Strategy For ThinkOrSwim

SilverWolf

Member
Sharing a script I modified to suit my trading. Works well and has options to adjust with market conditions. Little here little there Im no pro coder.. more like a script kid. If you have amendments changes improvements go for it. I currently trade ES. Tick charts I use intuition but usually between 150-600t I then adjust the moving average.. "what are the candles responding to" then minor tweak on the acceleration factor. I saved it here with general ES settings on a 500t chart.

I did my best to make it work on mobile app. You may have to change "signalsAtPSAR" from "Line" to "Arrow"... Should show up on mobile after that. I put in the option of using a single moving average like the 100 or use a crossing moving average to determine trend direction.

https://usethinkscript.com/threads/parabolic-sar-moving-average-trading-strategy.9533/
https://usethinkscript.com/threads/...-labels-charts-for-thinkorswim.515/post-29279

CSS:
# Parabolic_SAR_Moving_Average_Trading_Strategy

# 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 accelerationFactor = 0.012;
input accelerationLimit = 0.2;
input extremeoffset = 0.0;
input price = close;
input AvgType = AverageType.EXPONENTIAL;

input MovAvgTrendMethod = {default "SINGLE", "CROSSING"}; #('Crossing Avgs or Single Avg')
input CrossingLength = 19;
input TrendTriggerAvgLength = 40;

def Trend = if MovAvgTrendMethod == MovAvgTrendMethod."SINGLE" then 1 else
            if MovAvgTrendMethod == MovAvgTrendMethod."CROSSING" then 2 else 0;


#======== Moving Averages ======================================================================

plot TriggerAVG = MovingAverage(AvgType, close, TrendTriggerAvgLength);
TriggerAVG.SetDefaultColor(Color.white);


plot CrossingAVG = MovingAverage(AvgType, close, CrossingLength);
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]));
    }
}

#def PSAR = ParabolicSAR(accelerationFactor = accelerationFactor, accelerationLimit = accelerationLimit);




#======== SIGNALS =========================================================================


def BuySignal = if Trend == 1 and (close > TriggerAVG ) and (SAR crosses below close)

then 1

else if Trend == 2 and (close > TriggerAVG) and (TriggerAVG < CrossingAVG) and (SAR crosses below close)

then 1

else Double.NaN;


def SellSignal = if Trend == 1 and (close < TriggerAVG ) and (SAR crosses above close)

then 1

else if Trend == 2 and (close < TriggerAVG) and (TriggerAVG > CrossingAVG) and (SAR crosses above close)

then 1

else Double.NaN;






#======== STRATEGY ORDERS ===================================================================

#  if the buy signal was set, then set the stop loss to previous candle's low.

def buyStopLoss = if IsNaN(close) then buyStopLoss[1] else if !IsNaN(BuySignal) == 1 then low[1] else buyStopLoss[1];

#plot xbuystoploss = buyStopLoss; #Remember to hide on mobile app
#xbuystoploss.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);

#  if the sell signal was set, then set the stop loss to previous candle's high.

def sellStopLoss = if IsNaN(close) then sellStopLoss[1] else if !IsNaN(SellSignal) then high[1] else sellStopLoss[1];

#plot xsellloss = sellStopLoss; #Remember to hide on mobile app
#xsellloss.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);


def BuyExit = if (SAR crosses above price)# or (close <= buyStopLoss)

then 1

else Double.NaN;

def SellExit = if (SAR crosses below price)# or (close crosses above sellStopLoss)

then 1

else Double.NaN;


def LongEnt = BuySignal is equal to 1;

def ShortEnt = SellSignal is equal to 1 ;

def LongExt = BuyExit is equal to 1;

def ShortExt = SellExit is equal to 1;


AddOrder(OrderType.BUY_TO_OPEN, LongEnt, open[-1], TradeSize, Color.GREEN, Color.GREEN, name = "Buy Long");

AddOrder(OrderType.SELL_TO_CLOSE, LongExt, open[1], TradeSize, Color.RED, Color.RED, name = "Close Long");

AddOrder(OrderType.SELL_TO_OPEN, ShortEnt, open[-1], TradeSize, Color.ORANGE, Color.ORANGE, name = "Open Short");

AddOrder(OrderType.BUY_TO_CLOSE, ShortExt, open[-1], TradeSize, Color.WHITE, Color.WHITE, name = "Close Short");





#======== 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 LongEnt then LongEnt else Double.NaN;
LongEntrySignal.SetDefaultColor(Color.UPTICK);
LongEntrySignal.SetLineWeight(5);
LongEntrySignal.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_UP);


plot ShortEntrySignal = if ShortEnt then ShortEnt else Double.NaN;
ShortEntrySignal.SetDefaultColor(Color.DOWNTICK);
ShortEntrySignal.SetLineWeight(5);
ShortEntrySignal.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_DOWN);


#======== ALERTS ===========================================================================

Alert(BullSignalAtCandle, "Bullish PSAR", Alert.BAR, Sound.Ring);
Alert(BearSignalAtCandle, "Bearish PSAR", Alert.BAR, Sound.Ring);
Alert(BuySignal, "Bullish PSAR above AVG", Alert.BAR, Sound.Ring);
Alert(SellSignal, "Bullish PSAR below AVG", Alert.BAR, Sound.Ring);




#======== EOF =============================================================================
 
Last edited by a moderator:
mod note:
This post was edited.
In this forum, we only support the posting of scripts that use the open of the next bar for backtesting. It's important to remember that any strategy that plots on the close of the previous bar is not written correctly and will give you misleading results.
Now, we know it would be amazing to be able to go back in history and place trades after we know the outcome, but unfortunately, that's just not possible. That's why it's crucial to write your strategies using open[-1]. This way, the order price reflects the next moment in time - the open of the following bar. And in the real world, that's the earliest a trade can be placed.
Improved/Corrected Entry and Exit orders. Works well on mobile too

CSS:
# Parabolic_SAR_Moving_Average_Trading_Strategy

# 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 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"};
input TradeSize = 1;

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]));
    }
}


#======== SIGNALS =========================================================================




def BuySignal = if Trend == 1 and (close > TriggerAVG ) and (SAR crosses below close)

then 1

else if Trend == 2 and (close > TriggerAVG) and (CrossingAVG crosses above TriggerAVG) and (SAR < close)

then 1
else Double.NaN;


def SellSignal = if Trend == 1 and (close < TriggerAVG ) and (SAR crosses above close)

then 1

else if Trend == 2 and (close < TriggerAVG) and (CrossingAVG crosses below TriggerAVG) and (SAR > close)

then 1

else Double.NaN;


def BuyExit = if Closer == 1 and (close crosses below SAR[-1])

then 1

else if Closer == 2 and (TriggerAVG > CrossingAVG)

then 1

else Double.NaN;


def SellExit = if Closer == 1 and (close crosses above SAR[-1])

then 1

else if Closer == 2 and (TriggerAVG < CrossingAVG)

then 1

else Double.NaN;


#======== STRATEGY ORDERS ===================================================================
AddOrder(OrderType.BUY_TO_OPEN, BuySignal, open[-1], TradeSize, Color.GREEN, Color.GREEN, name = "Long");
AddOrder(OrderType.SELL_TO_CLOSE, BuyExit, open[-1], TradeSize, Color.RED, Color.RED, name = "Close");
AddOrder(OrderType.SELL_TO_OPEN, SellSignal, open[-1], TradeSize, Color.ORANGE, Color.ORANGE, name = "Short");
AddOrder(OrderType.BUY_TO_CLOSE, SellExit, open[-1], TradeSize, Color.WHITE, Color.WHITE, name = "Close");
#======== 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);

#======== EOF ===========================================================================
 
Last edited by a moderator:
UgIHu7X.png

Example of paper from mobile
 
Last edited by a moderator:
Hi Silver, Is there way you can add if the hourly chart has buy then all the lower times will only buy orders. Vice versa for short? Thank you
 
This strategy suffers from look ahead bias in the exit conditions for SAR. You cannot use [-1], it looks into the future. The only time using [-1] is appropriate in thinkorswim is to grab the Open[-1] price of the candle ahead where it enters. Otherwise, you're just being a future teller...
 
This strategy suffers from look ahead bias in the exit conditions for SAR. You cannot use [-1], it looks into the future. The only time using [-1] is appropriate in thinkorswim is to grab the Open[-1] price of the candle ahead where it enters. Otherwise, you're just being a future teller...
You are right and I have fixed this too but if you add few more of your own indicators along with this strategy results are great.

Can someone please add alerts to buy and sells?
 
@SilverWolf thanks for the stragety. Would it be possilbe to add color labels for buy, sell and close for the strategy to auto trade on macro recorder. Thanks.

Its not perfect and if someone has a better way please advise
try this:
CSS:
input simpleLabels = no;
AddLabel (simpleLabels,
if BuySignal  then  "         " else   "         ",
if BuySignal  then Color.GREEN else Color.WHITE);
AddLabel (simpleLabels,
if BuyExit then  "         " else   "         ",
if BuyExit then Color.MAGENTA else Color.WHITE);
AddLabel (simpleLabels,
if SellSignal then  "         " else   "         ",
if SellSignal then Color.RED else Color.WHITE);
AddLabel (simpleLabels,
if SellExit then  "         " else   "         ",
if SellExit then Color.LIGHT_GREEN else Color.WHITE);
 
Just so yall know I am currently working on a logic change where the system goes opposite when adx is under a specified filter. Really the only time this strat fails big is during consolidation. While trending its a moneymaker. So anyway.. when I get to a comfortable point Ill release it. Lets cross our fingers Im successful
 
Just so yall know I am currently working on a logic change where the system goes opposite when adx is under a specified filter. Really the only time this strat fails big is during consolidation. While trending its a moneymaker. So anyway.. when I get to a comfortable point Ill release it. Lets cross our fingers Im successful
I'm using your strategy to trade but using other indicators to confirm trades.
 

Join useThinkScript to post your question to a community of 21,000+ developers and traders.

Not the exact question you're looking for?

Start a new thread and receive assistance from our community.

87k+ Posts
201 Online
Create Post

The Market Trading Game Changer

Join 2,500+ subscribers inside the useThinkScript VIP Membership Club
  • Exclusive indicators
  • Proven strategies & setups
  • Private Discord community
  • ‘Buy The Dip’ signal alerts
  • Exclusive members-only content
  • Add-ons and resources
  • 1 full year of unlimited support

Frequently Asked Questions

What is useThinkScript?

useThinkScript is the #1 community of stock market investors using indicators and other tools to power their trading strategies. Traders of all skill levels use our forums to learn about scripting and indicators, help each other, and discover new ways to gain an edge in the markets.

How do I get started?

We get it. Our forum can be intimidating, if not overwhelming. With thousands of topics, tens of thousands of posts, our community has created an incredibly deep knowledge base for stock traders. No one can ever exhaust every resource provided on our site.

If you are new, or just looking for guidance, here are some helpful links to get you started.

What are the benefits of VIP Membership?
VIP members get exclusive access to these proven and tested premium indicators: Buy the Dip, Advanced Market Moves 2.0, Take Profit, and Volatility Trading Range. In addition, VIP members get access to over 50 VIP-only custom indicators, add-ons, and strategies, private VIP-only forums, private Discord channel to discuss trades and strategies in real-time, customer support, trade alerts, and much more. Learn all about VIP membership here.
How can I access the premium indicators?
To access the premium indicators, which are plug and play ready, sign up for VIP membership here.
Back
Top