Back to Community
Acquirer's Multiple, Based on "Deep Value" #Fundamentals

This algorithm seeks to replicate the strategy set forth in Tobias Carlisle's "Deep Value" See his Google Talk for a great summary of the strategy.

In "Deep Value" and in his first book, "Quantitative Value", Tobias demonstrates that the Enterprise Multiple or "Acquirer's Multiple", defined as Enterprise Value/EBIT outperforms all other value ratios. The books and their back-tests show that when ranking stocks based on the Enterprise Multiple, Value stocks (those with the lowest ratio of EV to EBIT) outperform Glamour stocks on the same spectrum.

As with many value strategies, this one holds no more than 30 stocks at a time and there are some additional filters, including a minimum market cap in the 40th percentile. Re-balancing is performed annually using data available as of the previous month, ideally. Hopefully future fundamentals API changes will allow more exact querying of variables on different timescales.

I'm not convinced that I am 100% faithfully replicating the strategy outlined in the book, but the results seem promising. One compromise I made was to allow negative EV/EBIT ratios. I think Tobias ruled these out, but they seem to contribute significantly to the performance.

Feedback is welcome!

Clone Algorithm
672
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Backtest ID: 54bf20cc055b5909864d6bdd
There was a runtime error.
34 responses

Your choice of Starting Time and Month of Rebalancing on backtesting is having so much influence on your end result.
Don't believe me? Then, try start backtest while market in (very) bullish stage, and this algorithm will vanish (end up behind from performance's index or just become trend following strategy).

Maybe because this algorithm is using value/fundamental strategy, and AFAIK these model of analysis eventually work contraversion/opposite from general market condition, although (usually) would became success on long term when market had go through bull/bear cycle. So, In my opinion, when market is in bearish then we may try this algorithm, of course after figuring out the bottom end/rebound phase and May the FORCE be with us...

This show backtesting start from 2 years ago, 100% with same algorithm..

Clone Algorithm
23
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Backtest ID: 54bfa12a20ad2409ef01bec8
There was a runtime error.

Starting time can have a big influence on value algorithms. They can outperform in bear markets and for long periods of time. That's why many people don't adhere to them. This algorithm also happens to be buying the most unloved companies. The theory is that it will outperform in the long run. The choice of starting month and day is based on the algorithm in the book, which identifies this as an academic standard. You can easily adapt to monthly re-balancing or annual re-balancing on another date.

Your more recent backtest distorts the results a bit because you start so far ahead of the first re-balancing day. So, the algorithm holds cash and then it becomes difficult to compare the results. Here's the same algorithm with the start date moved up to 06/25/2013 so that the start dates of the benchmark and algorithm are much closer. The benchmark still outperforms in the long-run, but the apparent disparity is less egregious. I think this effect has been discussed deeply in another thread: Returns.

Clone Algorithm
21
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Backtest ID: 54bfc6d86fea110753f8123b
There was a runtime error.

Yes, I understand. However, the point is actually I completely agree with you, about #value based algorithm. This algo should run on long term to be outperform the market, when the real #value will show itself.

And maybe I'm just still having the influence or some sphere when testing this algorithm with standard Quantopian Open Contest which is starting now. That's why I try to start simulating a backtest, exactly 2 years from now (Jan'13 --> Jan'15).

I'm just saying, this algo maybe looks not an attractive choice for short term running period(e.g: several months), moreover with the contest daily on judgement result, which is surely not an advantage point for any #value algo.

This is cool. Thanks for coding it up, Dan. AM is absurdly simple--rank on one factor EV/EBIT and buy the cheapest 30--but performs remarkably well. In a Russell 1000 universe (~ largest 1000 stocks) it has outperformed over the last two years starting 1/1/2013 and rebalancing after one year cumulatively returning 85.9% (CAGR 35.3%) vs 44.4% (CAGR 19.9%) for the R1000 TR. These are unusually good results. The last 10 years are more meaningful. Over the last 10 years (starting 1/1/2005) and measured on a rolling one-year basis in a Russell 1000 universe it has outperformed by an average of 9.6 percent and in 78 of 118 start date opportunities but underperformed in the following 40 one-year periods by an average of 6.3 percent:
4/16/12
3/19/12
2/21/12
1/23/12
12/27/11
11/28/11
10/31/11
9/6/11
8/8/11
7/11/11
6/13/11
5/16/11
4/18/11
3/21/11
2/22/11
11/29/10
10/4/10
9/7/10
8/9/10
2/22/10
1/25/10
9/8/08
8/11/08
7/14/08
6/16/08
4/21/08
1/28/08
12/31/07
12/3/07
11/5/07
10/8/07
9/10/07
8/13/07
7/16/07
6/18/07
5/21/07
12/4/06
11/6/06
4/24/06
3/27/06
2/27/06
1/30/06
1/3/06

Tobias,
So depending on the start date the algorithm will underperform the index, 1 in 3 chances?

Did I get that right ?

Over the last 10 years, yes.

Calendar based rebalancing will always affect results based on start time. That's why performance based rebalancing is a more reliable mode of security mashup.

Here's a backtest that goes back as far as the Quantopian data goes. Ideally, we'd be able to run backtests over multiple rolling time-frames automatically.

Clone Algorithm
672
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Backtest ID: 54c046696fea110753fd13f7
There was a runtime error.

Nice one, Dan. Almost double the return of the market over the full 13-year period.

Tobias, thank you for the presentation @ Google and sharing your research. I became aware of you first at that. I'd really like to mix in some x-factor along with the algorithm. By x-factor, I actually mean parameters derived from classics (Thornton O'Glove's Quality of Earnings, Schilit's Financial Shenanigans etc). My brain tells me that weeding out frauds and semi-frauds (companies that don't outright fudge earnings but conveniently transpose expenses and income from operating cash flows and investing cash flows), one should be able to minimize obvious risk.
I know this approach does go somewhat against your point of just following the model however my stubborn nature just tells me this would help. (I know it's not easy to tease out earnings quality from financial ratios but I've started down that path (mixed with an earnest reading through of 10Ks)
If I can mould that into an Algo here, I will.

Hey Sunil,

I just finished Tobias' first book Quantitative Value which gets into just those topics (ruling out frauds, etc.). The main algorithm described in the book is much more complex than the AM, but it would be interesting to see some of these additional filters tested against it. Some of this was done in the book, but I don;t recall if eliminating helped AM alone or not.

Quantitative Value is one of the best finance books I've read in the last couple of years. (Thanks Tobias and Wes!) Coding the QV algo is beyond my capabilities at the moment, but it's pretty clearly laid out in the book, so I hope someone will be able to do it here. If so, I am capable of breaking it. :-)

Hey Ron,

I haven't tried tackling it yet either, but I suspect the current fundamentals API is too limited at the moment to faithful reproduce many of the figures of merit. There's a lot of averaging of multiple past years' data and such that just isn't possible yet. It sounds like the Quantopian folks are eyeing this for the future though. I also recall another poster talking about trying to recreate the QV strategy here. Once the data is available, I'm all over it. I think the AM is easier, but QV lays out tons of useful tests that could be applied in other strategies.

I need to get back to working on this some more. In the meantime, here's the best results I've achieved in my past hacking.

Some of the changes I made:

  • Confirmed that negative EV is good (not really a change)
  • I exclude tickers that end in "_WI" - so-called "When Issued" shares that may indicate that a company is or was recently in the process of a bankruptcy or take-over. It would be good to understand this process better.
  • I try to only purchase a company once in a re-balance round - occasionally, two share classes of the same company show up in the universe, so I limit it to primary shares, as defined by the Morningstar API.
  • Only purchase common stock.
  • Exclude stocks trading under $5
  • I think I've improved re-balancing so that I am maximally utilizing cash available without using leverage. Need to dig on this more to be sure.

Things yet to come (not exhaustive):

  • Eliminate companies with negative EBIT or EBITDA. This may have to wait for a history-equivalent function for the fundamental data API.
  • Add an option to simulate commissions and slippage. This is a very inactive algorithm, so I suspect this will have little affect.
Clone Algorithm
672
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Backtest ID: 54c485f7eb6d0d09bffaeef9
There was a runtime error.

Hey Dan & Tobias!

I've amended your model Dan to not make purchases when the market is highly priced (shiller CAPE). This reduces quite a lot of losses (except 2008). This and reducing the portfolio size down to only 3, not a typo, 3. Seem to have created an unbelievable result. Around 1,388% over the last 14 years (21% annualised return). The sharpe is now 3.26 and sortino is 4.5.

I tried this with 4,5,6,7,8 etc - after around 8 the returns drop quite a lot and the model becomes much more sticky to the SPY price trend.

Question for Dan/Tobias - would this actually work in real life? Have I made a mistake/missing something? (This seems to good to be true)

Please let me know your thoughts when you can!

Clone Algorithm
543
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Backtest ID: 56c7b987da53350dd5d1203f
There was a runtime error.

Thanks for sharing. The result looks pretty amazing. I think we need to figure out how to get Shiller CAPE on-the-fly instead of hard-coded in the algo.

Any thought?

I agree - the best source I've found is the XLS on Yales website. It's constantly updated.

Can we read XLS files direct in Python?

I am using Yale's website as well. One way to work around might be to use build-in function of fetch_csv to read data from Dropbox as following.

fetch_csv('https://dl.dropboxusercontent.com/u/169032081/fetcher_sample_file.csv',  
               date_column = 'Settlement Date',  
               date_format = '%m/%d/%y')  

The only question I have is whether fetcher is supported for real-money trading yet? Another question is how to use fetcher to read-in excel file?

Hi all,

This looked interesting so I added a few things in as my first attempt at an algorithm. I haven’t seen any performance as good as the above results but I wanted to try adding some features. Specifically:
- I switched over to pipeline for the fundamentals data
- I added a filter based on this: https://www.quantopian.com/posts/how-to-filter-equity-types-or-classes-in-pipeline
- I found the CAPE data as a csv on quandl so I added a fetch_csv for it
- I added the Operating Earnings from http://acquirersmultiple.com/faq/
- I added a positivity filter
- It seems that Morningstar's ev_to_ebitda ratio uses the sum of the last 4 reported quarters for ebitda while their ebitda is just the last quarter value so I made an approximation of the annual ebitda by averaging the last year's daily values and multiplying by 4 (see, e.g. https://www.quantopian.com/posts/ev-slash-ebitda-value-then-momentum)
- I added a small check so the universe only updates at the end of the month

So far the results aren't nearly as good, and nothing comes close to using the built-in ev_to_ebitda ratio. I suspect it is because the filter using pipeline is not as capable (e.g. I can't filter out non-US stocks). Also, I still think there are some differences in how ev_to_ebitda is reported vs. estimating the ttm ebitda that cause very different results for some stocks.

And the backtest is pretty slow; I suspect there are some ways to access pipeline data more efficiently.

This is my first attempt at an algorithm and I'm fairly new to Python. Most of my ideas are based on reading posts from the forum. Hopefully some of this is useful. Let me know any feedback and ideas to improve the results. Thanks.

Clone Algorithm
58
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Backtest ID: 56fd6def698b270f373518c1
There was a runtime error.

I've ran the algorithm (1) between Jun 2008 and October 2016. Up and until Jun 2014 the algorithm seems to perform as expected beating the market, but from that point on it goes down, from Jun 2015 and onwards it tanks and the end result underperform the market by 44%.

(1) I've modified the algorithm to calculate ebitda_ttm (using last 4 quarters). I believe the ev_to_ebitda that comes out of the box uses last quarter's ebitda times four.

Clone Algorithm
34
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Backtest ID: 581189e9748539120f772c34
There was a runtime error.

Thanks Adam.

Maybe a little bit late, but for future users who want to use the algos listed above - be aware!!!:

The Algos listed above do not select deep value stocks, but instead the lowest EV-Ebitda ratio. The Algo therefore selects (nearly always) negative EV-Ebitda ratio, which is a result of negative Ebitda (not deep value and neither negative EV). The higher ranked stocks have a small negative EBITDA (i.e. EV=100 and EBITDA= -1 results in ratio -100, which is high ranked - ascending). It will never select good ratios in the range of 6-10.
With small effort you can filter out this error ...

Maybe just luck, that these algos turned out with these result. However, it shows if not a analysis is made on the selected stocks one tends just to look at performance of the algo (price) and not the intended goal. So you go astray....

Another thing, it would be nice if fundamentals were like a law of physics. I was surprised when I looked to determine the level of company inconsistency in reporting. There are 310 stocks whose ebitda changed only once over the last year according to this. Using FCount() from there, I'd be curious to know what you find adding a screen for ebitda value-change-frequency (first column here) above 4.0 for example. My stab at it in Mariano's code doubled the returns.

5.0 1123
4.0 714
3.0 7
2.0 4
1.0 310

In filters, instead of 'or' and 'and', use '|' and '&'. When I corrected those, returns went up further.

@CarloG mine filters ebitda > 0 and yet the results are the same.

ebitda > 0 and yet the results are the same

It is always positive. Pipeline preview is easy to add and shows column values. Here, I added an ebitda column.

    pipe.add(ev_to_ebitda, 'ev_to_ebitda')  
    pipe.add(ebitda,       'ebitda')  

Log:

                           min              mean               max  
      ebitda        55177000.0     571200633.333      2976000000.0  
ev_to_ebitda     1.66134270942     4.46710351926     5.65439201921  

@BlueSeahawk, made the changes you suggested but it doesn't seem to make much of a difference

Clone Algorithm
34
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Backtest ID: 5b04def88062bb43d5ba0b3f
There was a runtime error.

Try replacing roic from the original you copied, to ebitda. There were other changes you made, and in this I've merged some of them although not all. In particular you might want to re-add your new ebitda and ev factors. Also try FCount > 3, which would allow another 714 stocks in. Note that the fcount mask is QTradableStocksUS, so that is surely a major change too.

Clone Algorithm
12
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Backtest ID: 5b04f79e4eeb724479734786
There was a runtime error.

@Mariano: Sorry Mariano.
I might not been exact in my post. All algos, except yours, do not filter for positive ebitda (filter first introduced by you in Oct. 2016). All older algos in this thread did not select deep value stock, but just random stocks (not what the original intend was) with negative ev - ebitda ratio.
Of course your algo can still select negative ratio, but this stems from negative EV.

Here is my attempt, based on the comments in this thread. I'm using pipeline, the QTradeableStocksUS universe, and Q's Optimize API.

It picks the 30 stocks with the lowest EV/EBIT. Negative EBIT stocks are filtered out. Rebalances annually.

Backtest CAGR since 2003 is around 13.5%, pretty good for a strategy just picking one number and doing nothing the whole year. I could almost trade this.

Tobias' results in Quantative Value are 15.95% pa (1974 to 2011).

Clone Algorithm
36
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Backtest ID: 5bfbdfd29962e048cfd7eaf6
There was a runtime error.

I was wondering if anyone has tested the strategy with quarterly re-balancing? on one of the forums Toby said that for someone without tax constraints, quarterly re-balancing may enhance returns.

Couple of suggestions:
1. Run each fundamental in http://quantopian.com/posts/fundamentals-updating-daily-vs-monthly-or-quarterly to see how consistent they are.
2. For viewing the pipeline values easily and catching nans: http://quantopian.com/posts/pipeline-preview-overview-of-pipeline-content-easy-to-add-to-your-backtest
3. In custom factors, try forward filling nans and see whether that appears to be helpful or not. This is one way: http://quantopian.com/posts/forward-filling-nans-in-pipeline-custom-factors
I've always found these things eye-opening

Thanks @Blue for your pointers. After looking at 1, I see some cases. eg: Pfizer: from 11th to 14th Feb 2011, Revenue is updated but EBIT is not. I also could not reconcile the EBIT value with the SEC filing.

I've enjoyed my time looking at Q. But when I find missing data for an S&P 500 company which is a household name, I'm not sure if its worth continuing. One piece of missing quarterly data - the above for example, means I cannot test Pfizer for a whole year starting from 14th Feb 2011.