Back to Community
(Partial) implementation of Quantitative Value algorithm

Here's my implementation of the algorithm in Quantitative Value, following the discussion in this post. There are a few significant differences between this algorithm and the one in the book, owing to the difference between the Morningstar data and the data available to the authors. Also, Quantopian's data set extends back only 12 years, so putting in the full 8 year margin and franchise power computations didn't make a lot of sense. I also have not made any explicit effort in restricting the stock universe, save one stock that for some reason was breaking the backtest.

For this post I have removed several variations that have boosted returns to 750%, in part because they would distract from the core algorithm in the text. And also because the core algorithm seems a more sensible starting point for exploring other ideas. Note that there is no leverage and no short positions in this algorithm.

Clone Algorithm
Backtest from to with initial capital
Total Returns
Max Drawdown
Benchmark Returns
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: 575c9bc7f2d64f0f8d843735
There was a runtime error.
12 responses

Great Work! I was also working on the same topic but then stopped because of some Quantopian Limitation for Fundamentals data.
Where did you find that get_fundamentals supports a date also in the backtest environment and not only the research notebook? Is it an undocumented feature?

Here some links to my work on QVAL:
Campbell, Hilscher, Szilagyi (CHS) Model - Probability of corporate failure

Piotroski score:

Beneish score:

Hey Costantino,

You've just found a major bug in my implementation, get_fundamentals indeed does not take a date argument in the backtest. So I've been playing with an extremely partial implementation of the quantitative value algorithm, managing to squeeze out good performance from the few factors that are correctly implemented... This is beyond embarrassing, and quite frankly also really impressive that the broken algorithm produced this performance.

So the options I have now are to either save up state in the context object, which will not translate to the live trading environment, or to use pipeline, which at least used to perform horribly with fundamental data, to the point where the algorithm had to be broken up into phases that ran across multiple days. Ugh. I honestly don't understand some of the design choices that the quantopian platform has made.

Well, back to the drawing board.


Hi Sunil,

I wanted also to check, because I suspected that... anyway your work is a very good basis for the QVAL algorithm... it only needs to be updated, when Quantopian will make easier to work with historical fundamental data.

I'm complaining about the lack of this feature for a long time... if you query for my username, you will find many post about this subject.
There is a workaround, storing the data in a Panda Panel, but then is not possible to trade live (you have to wait a year o more before the panel is filled with data).

Q2 remains a great platform and maybe if we unite our forces, we can convince the Q-Team to add this feature as soon as possible ;-)... a get_fundamentalswith date like in the Research environment would be great!

Well, I'm slowly converting the algorithm over to use pipelines. So far I've only converted STA and SNOA computations, I suspect I'll soon run into timeout issues. Especially when I start implementing the franchise power and margin factors. The pipeline API as set up doesn't tell us where it is spending compute cycles, so any sort of optimization is virtually impossible.

I considered storing data in the context object, but as you said, that just doesn't work for live trading.

Another alternative to adding dates to get_fundamentals would be to allow specification of specific times for which we want to retrieve data for custom factors. Right now you have a very coarse window_size argument, would be good to be able to generalize that, even with something as simple as taking a vector of indices rather than a single window size.

The pipeline API is a really nice feature, but it is currently very inefficient especially when you want pipeline outputs infrequently (rather than daily), and does not come with a particularly rich set of operations that can be run on pipeline factors.


You're right! Pipeline API is nice but very memory consuming, when it comes to the many datapoints required for historical fundamental data.

I posted a feature request exactly as you're now proposing (vector of indices rather than a single window size):
but until now it remained a dead letter.

A kindly request to the Quantopian Team: get_fundamentals already supports timestamp and timeframe in the Research environment. It would be great, to enable the same also in the Backtesting!

I am for now giving up on fixing my implementation. I have posted a last cry for help here...

I've also been working on a QV screen algo, and running into the same issues as Sunil and Constantino when trying to run backtests.

However, I have put together a notebook (using pipeline) showing my working and would love thoughts / inputs from others. I already know there are a few things that need working on, for example:

  • some of Constantino's examples above seem to have more accurate ways of determining window sizes and indexing for fundamentals - I need to look at that
  • I still have to implement the 'probability of manipulation' part of the forensic screen
  • my franchise power factors only go back a maximum of 2 years, as opposed to 8 - notebook might be able to handle more than 2 years, I need to look at that

If you spot any other bugs or have any other suggestions for improvement, please let me know. Otherwise I'm just going to be waiting for Constantino's feature request above to be implemented :)

Loading notebook preview...
Notebook previews are currently unavailable.

After working with the QV algorithm for a few months, here's what I've learned:

  1. The algorithm has been developed and optimized for long term investing with annual rebalancing. The outcome is quite tax efficient for an individual investor. It isn't necessarily the kind of thing that fits into the Quantopian hedge fund. However, you can improve performance a bit if you add in momentum and technical factors. I've used regression lines with some success.
  2. Large parts of the algorithm can't be implemented using Quantopian's current pipeline implementation. Getting over an year of data (that's two data points per factor) is infeasible. You end up consuming too much memory, it kills the notebook.
  3. There are large holes in the morningstar data. Many factors are defined for surprisingly few companies. EBIT for instance is defined for about 1000 fewer companies than EBITDA. Look at the fundamental data you're using carefully. I've developed notebooks to get a sense for the data cardinality. I'd post a link for the notebook, but the forum refuses to attach them to a message. I'll see if I can share them via bitbucket.
  4. On a related note, most fundamental factors seem to be updated on a quarterly basis. The QV text I believe prefers annual numbers. Quantopian's infrastructure can't accommodate annual aggregation particularly well due to memory issues noted above.
  5. There are outright errors lurking in the fundamental data. These can be really hard to spot.

I might try running some experiments again in the future if Quantopian fixes issues surrounding fundamental data access.


thanks Sunil

Thank Sunil, yeah I found many NaN values in the fundamental data too. I think this algorithm may be better used as a screener rather than a trading algorithm, at least with the current data availability.

Some updates:
- Use today's date.
- Remove stocks with NaN total_assets (i.e. fundamental data of some companies like CVE, UBS, etc. do not get listed in Quantopian dataset as they filed as foreign issuers).
- Get all companies instead of only ones with high AverageDollarVolume.
- Use 8-year factors for growth. The code looks incorrect but I cannot confirm at the moment. Will look more into this later.

Loading notebook preview...
Notebook previews are currently unavailable.

Jay Teguh Wijaya - amazing notebook!!! thanks... you saved me weeks of work