Close() v. CloseExDiv() v. Price

Dear P123 staff or experienced users,

Apologies in advance for the long post with lots of questions, but I’m quite confused by the differences between and appropriate uses for Close(), CloseExDiv(), and Price… even after reading and rereading the forums and documentation several times. Specifically…

What does it mean that Close() reverses out future splits? Let’s say a stock is at $10 twenty bars ago, and then goes to $5 zero bars ago because of a 2:1 split. Reversing out the split to me sounds like we’re going to pretend the 2:1 split never happened and we’ll say the stock remains at $10 zero bars ago even though it’s actually trading at $5 in real life. So, that would mean that Close(10) equals $10. That seems wrong, but that’s what reversing out future splits means to me.

What does it mean that Close() is adjusted for dividends? Let’s say a stock is at $10 twenty bars ago, and then goes to $9.50 zero bars ago, and there’s a $0.50 dividend in between. To say it’s adjusted for dividends sounds like Close(0)=$10 even though the stock is actually trading at $9.50 zero days ago. This seems wrong, but that’s what adjusting for dividends sounds like to me.

If I use “Close(0)/Close(20)-1” will that 4-week percentage return be distorted by any intervening splits or dividends? Is that ratio essentially the same as either Pr4W%Chg or TotalReturn4W?

If I use Close(0)InsNetShrPurch in a sim, am I accurately estimating the $ value of net insider purchases? Or, should I use PriceInsNetShrPurch? Is the seemingly more accurate estimate “VMA(126)*InsNetShrPurch” using the right price even if there were splits that happened in the past?

Documentation states that Price is unadjusted for splits. Is it also unadjusted for dividends?

Is there a good reason to ever use CloseExDiv() or Price? What would some examples be?

CloseAdj() is the only one I think I actually understand… I think it’s basically designed to be a time series that sets the current price to be an accurate real-world price and every price before that is adjusted for future splits. Therefore, all past CloseAdj() values never actually happened in real life if there were splits. Although, I’m not exactly clear on how CloseAdj() treats dividends…

Thanks in advance to anyone who can help!

Close(0)/Close(n)-1 gives the total return; as if you would have bought n trading days ago and held until today while reinvesting dividends. Close() gives us what Yahoo Finance calls the adjusted price.
CloseAdj(n) is the point in time price that you would have gotten if you had a time machine and went back to that day. It ignores dividends. It has a serious look ahead bias because of splits.

I have been working this out and would like to respond in detail. I need to consolidate my thoughts, so stay posted for my response.

In the recent past, I too have asked some of these questions in the thread, “The right price for fundamental data: adjusted or unadjusted close?”. While I am not able to answer precisely the formulaic approaches used by P123 to determine Close(), CloseAdj(), and CloseExDiv(), I might be able to set you on the right path for understanding which functions to use and when.

Data for Backtesting” is required reading for understanding how P123 has standardized fundamental data items so that data today can be compared to data in the past. Page 2 of of the guide clearly highlights the importance of understanding how share counts and other fundamental line item data point have been adjusted where the author states, “It’s interesting that we don’t get nearly as many questions on these topics as might be expected given their importance to proper testing”. For example, how you would calculate sales growth could differ depending on if its measured from the shareholder’s point of view or the enterprise’s; the answers may differ significantly depending on corporate actions. I.e., SalesQ/SalesPYQ != SalesQ/FHist(“SalesQ”, 52).

A good way to understand how P123 normalizes data is to compare how it defines “point in time” versus “historical” through examining the behavior of functions nested with the “FHist()” function. Point in time is defined as “looking back at data today as it would’ve looked then if splits were reversed”. P123 defines historical as “looking back at data as it looked then, unadjusted for corporate actions that have taken place since then”. In a related post entitled "Shares outstanding ", Marco explains:
“The output of FHist is point in time only for the offset to which it resolves to. Ex, FHist(“xyz”,10) used today, returns xyz point in time as of 10 weeks ago. Whatever happened in the past 10 weeks is not included…[FHist is] best used for ratios where the #shares is normalized away, like PE, mktcap, etc.”

The post entitled, “Custom Benchmark / Index”, shows you how to use share functions with fundamental data to create capitalization weighted benchmarked. CloseAdj() should only be used by itself and/or for creating smooth equal dollar-weighted benchmarks. In fact, I recently observed that CloseAdj() can no longer be called from the screener. Doing so result in the following: “ERROR: CloseAdj() is only available in the Series creation tool”. I haven’t found many use case for CloseAdj() anyway.

As Marco points out in a post about the deprecated CloseAdj() function , users should combine “Close() with line item functions from FUNDAMENTALS->STATEMENTS & FILINGS”. Likewise, when I asked in a previous feature release about the “correct” way to compute capitalization weighted benchmarks and factors, Marco replied that you SHOULD NOT use CloseAdj() in conjunction with fundamental data; he adds:
CloseAdj is a series fully adjusted for all splits, even when used in the past. It’s needed in the series tool to create smooth benchmarks. CloseAdj should only be used by itself because everything else is point in time, like CurFYEPSMedian. Use Close() instead.”

I think there is partial answer here for all your questions except:

  • “Is there a good reason to ever use CloseExDiv() or Price? What would some examples be?”
    Honestly, I don’t know where I would ever use CloseExDiv() or Price. In fact, from my initial look at it, PricePY appears to be split adjusted. Compare showVar(@LastYrCloseC, FHist(“Price”,52)) vs showVar(@LastYrCloseB, PricePY) in screener.

SP500 Rtn Calculated.JPG

Chipper - I think your definition of CloseAdj(n) seems wrong, at least the part about it being what you would have seen with a time machine if you went to that day in the past. At the very least, your definition seems to contradict Marco’s statement that it’s a series fully adjusted for all splits even when used the past. Let me know if I misunderstood your statement…

Primus - Thanks for the detailed post. I spent some more time on this and I have a few beliefs about how this works.

Set variables:

  1. @close = Close(n)
  2. @div = DivPSDays(Trunc(n*365/251),0,#AllDiv,#ExDate,FALSE)
  3. @split = SplitFactor(Trunc(n*365/251))

Beliefs:

  1. Historical price n bars ago = (@close + @div)*@split // By ‘historical price’ I mean the time machine price that Chipper referred to.
  2. Close(n) = CloseExDiv(n)-@div
  3. Close() and technical indicator functions like VMA() will always be comparable since they’re both split and dividend adjusted.
  4. Price and PY seems irrelevant and not worth understanding
    
  5. InsNetShares seems not worth understanding until your feature request goes through since most of the current data is not open market purchases
    

I tested beliefs #1 and #2 and I seem to usually get both sides of the equation to be pretty close, although there’s often a difference of a few pennies that I can’t explain, so it’s possible I’m still missing something. Would be helpful if a P123 staffer could set the record straight.

I’m also now confused about CloseAdj()

  1. What’s the actual formulaic expression for CloseAdj()?
  2. Marco says that CloseAdj() is necessary when you want to create a smooth series in custom series but why can’t Close() do the same thing.
  3. How would one use CloseAdj() in custom series without causing a look ahead bias?

Thanks!

P123 is a time machine with every function, so anything that happens in the future of the as-of date of the analysis is like it never existed. When you think about it that way hopefully it helps.

Except for CloseAdj()

CloseAdj() is simply the price series fully adjusted for all splits that have occurred up until today. This function is only available in the Series tool for a very specific purpose: to allow the creation of custom indeces. Take a look at this series: Internet4-Benchmark . Try using Close() instead of CloseAdj() and you will see the problem. Also, using CloseAdj() is not really a look-ahead bias since this “index” series would be used to spot trends. The actual series value is irrelevant.

In conclusion we added CloseAdj for creating benchmarks in the series tool. Any other use is probably wrong. Please ask us when in doubt.

I think I’m beginning to see the light.

Tamak,

You’re formulas looked pretty darn good when I get checked things out. Excellent work! The only small change I made was to your 251-to-365 day calendary year conversion. I represented this as:
ShowVar(@n_adj, Trunc(@n251/365)+ eval(Mod(@n251,365) >= .5, 1, 0)) // trading days, 251 day calendar basis
… which is essentially rounding instead of truncating.

Marco,

Do you see anything wrong in the way I calculated a capitalization weighted benchmark here ? I didn’t use CloseAdj() because it’s not comparable with other lines items including shares. Are there any adjustments I could make?

Thanks Marco. I think I understand now.