Friday, May 16, 2014

thinkscript included: sdi_psarstgy - simulate trading the parabolic-stop-and-reverse signal

i was listening to swimlessons on thinkorswim today and i heard jeff bierman promoting the psar (parabolic-stop-and-reverse) strategy. so i was wondering how this strategy really performs when you add up the wins and losses. this is the inspiration for my new sdi_psarstgy thinkscript strategy and here is what i find with the standard recommended settings of .02 for acceleration factor and .2 for acceleration limit:
p&l of $10k traded by the psar strategy (using standard .02 acceleration-factor and .2 acceleration-limit parameters) on spy compared with growth of  $10k buy 'n hold (bottom green) and dollar-cost-averaging (bottom blue)
the psar strategy lost $746 while buy 'n hold made $1,269 and dollar-cost-averaging made $678 - not exactly a happy picture but jeff did say you need to adjust the acceleration parameters. by tweaking the input parameters to my sdi_psarstgy one can instantly evaluate the effect a modification has to the p&l. here's a setting that turns the above frown upside down:
p&l of psar strategy with acceleration factor of 1.0 and acceleration limit of 0.3

this p&l is nearly the same as buy 'n hold and handily beats dollar-cost-averaging. the acceleration factor of 1.0 says to the psar formula to skip the pretty parabolic movement of the stop and go immediately to the straight-line movement set more aggressively at 0.3

here's the code (install instructions here):
# sdi_psarstgy:
#hint:Strategy to evaluate trading parabolic-stop-and-reverse signals rev:1.1.0
# author: allen everhart
# date: 16may2014
# revisions:
#    4jun2014-added %win label, corrected reverse price on gaps
input dollarsPerTrade = 10000;
#hint dollarsPerTrade: trades vary in share size in order to keep the invested dollars constant to create a fair comparison to passive strategies. rev: 1.1.0
input accelerationFactor = 0.02;
#hint accelerationFactor: controls how steep a parabola is traced by the stop.
input accelerationLimit = 0.2;
#hint accelerationLimit: after the limit is reached the stop moves up in a straight line.

def psar = ParabolicSAR( "acceleration limit" = accelerationLimit, "acceleration factor" = accelerationFactor);
def buySig = close crosses above psar;
def sellSig = close crosses below psar;
def shareSize = round(dollarsPerTrade/psar,0) ;
def buyPrice=#psar;
    if open[-1]>psar then open[-1]
    else psar;
def sellPrice= #psar;
    if open[-1]<psar then open[-1]
    else psar;
AddOrder(OrderType.BUY_AUTO, buySig[-1], price = buyPrice, tradeSize=shareSize, name = "buy");
AddOrder(OrderType.SELL_AUTO, sellSig[-1], price = sellPrice, tradeSize=shareSize, name="short");
plot parSAR = psar;

def longPrice=compoundValue(1,
    if !longPrice[1] && buySig[-1] then buyPrice
    else if longPrice[1] && sellSig[-1] then 0
    else longPrice[1]
#plot lp=longPrice;
def shortPrice=compoundValue(1,
    if !shortPrice[1] && sellSig[-1] then sellPrice
    else if shortPrice[1] && buySig[-1] then 0
    else shortPrice[1]
#plot sp=shortPrice;

def wincntr= compoundValue(1,
    if longPrice[1] && sellSig[-1] && sellPrice>longPrice[1] then wincntr[1]+1
    else if shortPrice[1] && buySig[-1] && shortPrice[1]>buyPrice then wincntr[1]+1
    else wincntr[1]
def winNum=if isnan(wincntr) then winNum[1] else wincntr ;
def losscntr= compoundValue(1,
    if longPrice[1] && sellSig[-1] && sellPrice<=longPrice[1] then losscntr[1]+1
    else if shortPrice[1] && buySig[-1] && shortPrice[1]<=buyPrice then losscntr[1]+1
    else losscntr[1]
def lossNum=if isnan(lossCntr) then lossNum[1] else lossCntr ;

    concat( "win: ", 
    concat( round( 100*winNum/(winNum+lossNum),1),
    concat( "% of ", winNum+lossNum))),


  1. Interesting. Resetting the parameters to 1.0 and 0.3 really shows a report of profit. The other showed the opposite. How did you come to this conclusion? Maybe guess and check, but finding the right parameters probably comes by knowing how the strategy works.

  2. This comment has been removed by the author.

  3. 1 is the limit and 0.3 gives the greatest amount of profit along with the least amount of orders.

    1. Alas, no. 1 is the factor initialization and .3 is the limit. The idea was to concentrate on getting the correct limit by 'pinning-out' the factor i.e. initializing it to a number greater than limit so that the limit would be the effective factor. However, a careful reading of the source code of the TOS implementation of psar leads me to believe that if factor is initialized greater than limit then this initialization is in effect until the first extension of range, after which the limit goes into effect. Thus, this 1/.3 setting produces giant-steps in the movement of the stop until the initial extreme point is crossed and baby-steps thereafter. I think this behavior is unintended but is an interesting concept that may actually help to mitigate loss during consolidation periods.

  4. Hi Allen,

    I just wanted to comment and say thanks to you for putting up this script. I have had unbelievable success trading s & p 500 emini futures with your optimized psar settings. This has been a true game changer for me, and sometimes I can't believe turning a profit can be this easy, even when only trading a single contract. Again, thanks a bunch, and keep doing what you do!

  5. I am just coming across your work and after adding the study to TOS it didn't work.....does the code still work?

    1. hi, please note that this is a 'strategy' not a study. the difference is the addorder() functions will give you problems if you copy 'n paste into a new study. to be sure, i was successful just now in copying and pasting this code into a new 'strategy'

  6. Thank you for your quick reply. That did the trick. I will play around with this

  7. love it, but is there a way to change the sharesize to work with futures where a margin req would be $4500 but each tick would be $10 (crude). If I put 10 it goes to 0? any ideas?