Saturday, June 4, 2011

sdi_seapro5 - 5 Season Projection Of Price (deprecated)

(Note: this fixed 5-season version of seasonal projection has been deprecated. This means I am freezing all updates to this software. Instead of using sdi_seaproj5 I would suggest my sdi_seaproj which permits the user to specifiy the number of seasons that are averaged into the projection.)

One of the TOS studies I had been holding back is SeaPro, Seasonal Projection of price. This study averages the fractional seasonal moves from a reference date and projects the average into the future. Here's an image of SeaPro5 in action:

  • How todays price might move if this was last year or two years ago
Internally, SeaPro calculates the fractional moves that the stock made in a previous season and multiples these against the last closing price to create an individual seasonal projection. It's like asking how todays price might move if this was last year or two years ago or in the case of the above image every fourth year. Then the individual seasonal projections are averaged together to produce a projection average, the solid blue line.
  • Theoretically, seasonality should be factored into the implied volatility
In as much that the individual seasonal projections are the measure of what's to come, the projection average can be said to be predictive, which is why it plots to the right of the prices in the chart. If you use this study on a 1day/1year chart you will need to adjust your settings to show 252 or so bars to the right to see a full years projection. Theoretically, seasonality should be factored into the implied volatility, in that traders could know this information and bid the price of options accordingly.  So this study just gives you a way to visualize seasonality better when some commentator says there is a seasonal bias in play.
  • The area between the projection average and the flat line is high probability for recurrance.
The dashed blue line is the flat line, which is obvious, but until I actually plotted that line it did not occur to me take notice of the area between the flat line and the projection average. If the projection average represents even odds for recurrance then the area between the projection average and the flat line is high probability for recurrance.
  • What track through the high probability area, between flat line and projection average, is important for my trading?
The next question I wanted to know the answer to is: what track through the high probability area, between flat line and projection average, is important for my trading? If you plot standard deviation lines above and below a projection average then statistics tells us that 84% (=.5 * 68 + 50) of the individual seasonal projections track above the lower standard deviation line (and vice versa for the upper standard deviation.) For most any stock with a strong uptrending projection average it can take months for a lower standard deviation line to move above the flat line. Most option traders, like me, have a shorter time frame, so we are willing to go with less probability (as long as it is greater than a coin flip) if a modest advance can be achieved more quickly. This was the inspiration for that splash of green on the chart that I call the HPI, High Probability Indicator.
  • 62% of the individual seasonal projections track above this lower HPI 
The line of the HPI, by default, tracks .3 times a standard deviation away from the projection average. Statistically it can be shown that 62% of the individual seasonal projections track above this lower HPI (and vice versa for the upper HPI.) Only the part of the HPI line that tracks between the flat line and projection average is shown and only when it tracks 2%, by default, or more away from the flat line. So when I see a swath of green from the HPI I know that it is saying that there is a relatively strong bullish seasonal edge in play. If there is just a few splashes of green here and there then there is a weak case for seasonality.

  • A Trio Of Studys
 I have in my arsenal two other variations of SeaPro, seven and fifteen season versions I call SeaPro7 and SeaPro15. Due to limitations of ThinkScript it is not possible to write a dynamic version of SeaPro that self-adjusts to the number of seasons of data available for any given equity so if you come across a relatively new equity you might find that the projection simply does not display. Experience has shown me that SeaPro5 is the most versatile version because it can show the Presidential Cycle (on a weekly chart) to an earnings cycle and everything in between.

# sdi_seaPro5: 5-Season Seasonal Projection Of Price
#hint: Displays a seasonal projection of price based on the average fractional price move between the anchor date and same seasonal dates in the past. Also shows an indicator of high probability of exceeding-on-date (hpi.) Triangles decorate the HPI when 3 or more seasons exceed it. rev:1.9.1
# author: allen everhart
# date: 17Dec2010
# copylefts reserved. This is free software. That means you are free
# to use or modify it for your own usage but not for resale.
# Help me get the word out about my blog by keeping this header
# in place. 
input trailAnchor = 0; #hint trailAnchor: Sets Moving anchor date to n-bars ago. Takes precedence over anchorDate.
input anchorDate = 0; #hint anchorDate: Sets fixed anchor date. Format: YYYYMMDD.
input seasonLen = 252 ; #hint seasonLen: Sets number of bars in a season. <br>252=1yr on US-equity, daily charts. <br>63=3mo qtr on US-equity, daily charts. <br> 260=1yr FX & Futures daily charts. <br>52=1yr on weekly chart.
input hpIsoline = { "54%", default "62%", "73%", "84%", "90%", "hide" }; #hint hpIsoline: Sets exceed-on-date probability for hpi.
input hpiMinPct = 2.0 ; #hint hpiMinPct: Sets profit filter for hpi.
input individualSeasons = { default hide, show}; #hint individualSeasons: show the projection of individual seasons. Most recent 3 are lime-colored, oldest are grey.
input stdMultiple = 0.0; #hint stdMultiple: Multiple of the standard deviation to show. Zero to hide.
#input version = { hide, default show }; #hint version: show script version as a chart label.
#AddChartLabel( version ==, "sdi_seaPro5 v:1.7.0" );
# v:1.9.1 - 5/19/2012 clsy(n>0) was referencing close from 1 bar too recent. fixed.
# v:1.9.0 - 3/30/2010 hide bubbles - prevent bloat.
# v:1.8.0 - 8/30/11 deprecate the version label - version in hint
# v:1.7.0 - simplify - remove envelope and spike analysis
# v:1.6.0 - expand the choice on standard deviation multiples.
# v:1.5.2 - fixes bug w. originDate not propagating forward correctly
# v:1.5.1 - fixes spurious incorrect color on hpi

def x = if hpIsoline == hpIsoline."54%" then 0.1
else if  hpIsoline == hpIsoline."62%" then 0.3
else if  hpIsoline == hpIsoline."73%" then 0.6
else if  hpIsoline == hpIsoline."84%" then 1.0
else 1.3;
rec originDate =
  if trailAnchor > 0 && IsNaN(close[-trailAnchor]) && IsNaN(close[-trailAnchor - 1]) then
  else if trailAnchor > 0 && originDate[1] > 0 then # 1.5.2 added [1] to originDate
#plot od = originDate;

# pn is the number of bars past the originDate
rec pn =
  if !pn[1] && getYyyyMmDd()[1] < originDate && getYyyyMmDd() >= originDate  then
  else if !pn[1] && IsNaN(close) && !IsNaN(close[1]) then
  else if pn[1] > 0 then
    pn[1] + 1
#plot p=pn;
rec clsy0 =
  if pn == 1 then close[1]
  else if pn > 1 then clsy0[1]
  else 0;
plot fl = if pn > 0 then clsy0 else double.NaN; # flat line
fl.SetStyle(curve.SHORT_DASH) ;

rec clsy1 =
  if pn == 1 then close[seasonLen+1]
  else if pn > 1 then clsy1[1]
  else 0;
#plot fl1 = if clsy1 > 0 then clsy1 else double.NaN;
rec clsy2 =
  if pn == 1 then close[(2 * seasonLen) +1]
  else if pn > 1 then clsy2[1]
  else 0;
#plot fl2 = if clsy2 > 0 then clsy2 else double.NaN;
rec clsy3 =
  if pn == 1 then close[(3 * seasonLen) +1]
  else if pn > 1 then clsy3[1]
  else 0;
#plot fl3 = if clsy3 > 0 then clsy3 else double.NaN;
rec clsy4 =
  if pn == 1 then close[(4 * seasonLen) +1]
  else if pn > 1 then clsy4[1]
  else 0;
#plot fl4 = if clsy4 > 0 then clsy4 else double.NaN;
rec clsy5 =
  if pn == 1 then close[(5 * seasonLen) +1]
  else if pn > 1 then clsy5[1]
  else 0;
#plot fl5 = if clsy5 > 0 then clsy5 else double.NaN;

def y1 = close[1 * seasonLen] / clsy1 ;
def y2 = close[2 * seasonLen] / clsy2 ;
def y3 = close[3 * seasonLen] / clsy3 ;
def y4 = close[4 * seasonLen] / clsy4 ;
def y5 = close[5 * seasonLen] / clsy5 ;

plot p1 = if pn > 0 then clsy0 * y1 else double.NaN;
plot p2 = if pn > 0 then clsy0 * y2 else double.NaN;
plot p3 = if pn > 0 then clsy0 * y3 else double.NaN;
plot p4 = if pn > 0 then clsy0 * y4 else double.NaN;
plot p5 = if pn > 0 then clsy0 * y5 else double.NaN;

p1.setHiding(individualSeasons == individualSeasons.hide);
p2.setHiding(individualSeasons == individualSeasons.hide);
p3.setHiding(individualSeasons == individualSeasons.hide);
p4.setHiding(individualSeasons == individualSeasons.hide);
p5.setHiding(individualSeasons == individualSeasons.hide);


def yavg = (y1 + y2 + y3 + y4 + y5 ) / 5;
plot pa =
  if pn > 0 then
    (p1 + p2 + p3 + p4 + p5 ) / 5

def hpiUpTarg = clsy0 * (1 + (hpiMinPct / 100));
def hpiDnTarg = clsy0 * (1 - (hpiMinPct / 100));

def pstd = Sqrt((Sqr(p1 - pa) + Sqr(p2 - pa) + Sqr(p3 - pa)
+ Sqr(p4 - pa) + Sqr(p5 - pa) ) / 5);
plot psdu = pa + (pstd * stdMultiple);
plot psdd = pa - (pstd * stdMultiple);
def hpul =  pa - (x * pstd);
def hpll =  pa + (x * pstd);
plot hpi = # High Probability isoline
  if pn > 0 && pa > clsy0 && hpul >= hpiUpTarg then
  else if pn > 0 && pa < clsy0 && hpll <= hpiDnTarg then
hpi.AssignValueColor( if hpi > fl then color.GREEN else color.RED );
AddCloud( hpi, fl, color.GREEN, color.RED );
hpi.setHiding(hpisoline == hpisoline.hide);
def nup =
  (if p1 >= hpi then 1 else 0)
  + (if p2 >= hpi then 1 else 0)
  + (if p3 >= hpi then 1 else 0)
  + (if p4 >= hpi then 1 else 0)
  + (if p5 >= hpi then 1 else 0)
#plot pnup = if pn>0 then nup else double.NaN ;
def ndn =
  (if p1 <= hpi then 1 else 0)
  + (if p2 <= hpi then 1 else 0)
  + (if p3 <= hpi then 1 else 0)
  + (if p4 <= hpi then 1 else 0)
  + (if p5 <= hpi then 1 else 0)
plot n =
  if pn > 0 && yavg > 1 && nup > 3 && hpi >= hpiUpTarg then
  else if pn > 0 && yavg < 1 && ndn > 3 && hpi <= hpiDnTarg then
  if n > clsy0 && nup > 4 then color.MAGENTA
  else if n < clsy0 && ndn > 4 then color.MAGENTA
  else if n > clsy0 then color.GREEN
  else color.RED
n.setHiding(hpisoline == hpisoline.hide);



  1. Thank you for sharing this indicator. I've plotted it on my TOS chart and have allotted a 23 day expansion to the right of the chart. What do the green dots and green arrows on top of the "splash of green" on the chart mean?
    Am trying to spread trade weeklys. What would be the "safe" zone to place a credit spread? Below the "flat line"? Thanks again!

    1. Or above the "projection" line as well?

    2. The green splash is the area between the flat line and the lower bollinger-like line of the projection average when it rises 2% or more above the flat line. In the default settings I use a multiplier of 0.3 std for the bands because it can be shown, mathematically, that 64% of the seasonality projects to higher values than this lower band. For me this represents minimal reliability to be actionable for trading, after all one can draw an average line through any set of randomly selected prices. The triangles represent where 4 or 5 of the projections exceed (or subceed on bearish seasonality) the projection. I don't find the triangles to be terribly more actionable than the splash indicator, though.

  2. This is great! A previous teacher advocated a lot of manual research like this to take advantage of earnings plays. Now I am a convert to TastyTrade and your indicator is a huge help to maximize POP. Is there a way to do a similar code to forecast IV rank and pending IV rank collapses? Seems that seasonality may apply.

    1. Interesting idea. I might get around to writing something like that eventually.