Back to Community
Value Momentum Strategy

Hi, I am new to Quantopian. I was playing around with Johnny Wu's "EV/EBITDA Value, then momentum" strategy and got some good results with a few tweaks (although it seems like it hasn't performed well since 2014). Are there any obvious issues with my criteria? I allow stocks with market cap > $1m and share count < 200m which makes illiquid stocks an issue. How does the backtester handle low volume and wide bid/ask spreads? Does it determine how much of the stock's volume you can get filled on and does it just cross when buying/selling? And how would I filter against illiquid stocks if I wanted to? I did not see anything in the filter for share price, average volume, or anything like that. If I were to use this screen for live trading, are there any issues that I should look out for? Thanks.

Clone Algorithm
299
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: 556cd8b89bc1f510a054257e
There was a runtime error.
24 responses

Hey Walter,
We use a slippage model that is customizable in the backtest. See our help page for information about that. We don't currently have bid/ask spreads, we use trade data for every security. Orders submitted in one bar are filled in the next bar. For transitioning from backtesting to live trading, I would read the relevant points on the help page — it's tough to say if something is going to run OK on live trading. It usually does, but yeah, read through and make sure. You can also use paper trading to test live trading before you transition to real money.

As you're doing, you can filter out a lot of stocks by using the fundamentals API. You could also filter more at other places in your code. For example, you could do:

if data[stock].volume > 200000:  
    ...  

To check if a stock has volume over 200,000 in handle_data. This uses the data object. Let me know if you need any more help with that.

Gus

Disclaimer

The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by Quantopian. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. No information contained herein should be regarded as a suggestion to engage in or refrain from any investment-related course of action as none of Quantopian nor any of its affiliates is undertaking to provide investment advice, act as an adviser to any plan or entity subject to the Employee Retirement Income Security Act of 1974, as amended, individual retirement account or individual retirement annuity, or give advice in a fiduciary capacity with respect to the materials presented herein. If you are an individual retirement or other investor, contact your financial advisor or other fiduciary unrelated to Quantopian about whether any given investment idea, strategy, product or service described herein may be appropriate for your circumstances. All investments involve risk, including loss of principal. Quantopian makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances.

I thought it would be fun to see if I could get the beta lower in this algo - at least low enough to be in the .3 to -.3 range needed for the Quantopian Open

As a quick solution, I threw in a short of SPY with half the portfolio value and reduced the weights of the long positions by half to keep leverage under 1.

The beta came down from .95 to .21, which would make the cut.

The returns and Sharpe Ratio were dampened significantly but the max drawdown also came down from a gut-wrenching 54% to an almost livable 14% (in other words, it handles 2008 a little better :)

There's probably better ways to hedge here by finding a specific bucket of stocks to rank and short. Also, the leverage bounces between .5 and 1 weirdly. Probably a better way to rebalance with the short in the algo . . . but it was fun to try out and play with.

Clone Algorithm
69
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: 556f5f3fdb7c461092dd0730
There was a runtime error.
Disclaimer

The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by Quantopian. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. No information contained herein should be regarded as a suggestion to engage in or refrain from any investment-related course of action as none of Quantopian nor any of its affiliates is undertaking to provide investment advice, act as an adviser to any plan or entity subject to the Employee Retirement Income Security Act of 1974, as amended, individual retirement account or individual retirement annuity, or give advice in a fiduciary capacity with respect to the materials presented herein. If you are an individual retirement or other investor, contact your financial advisor or other fiduciary unrelated to Quantopian about whether any given investment idea, strategy, product or service described herein may be appropriate for your circumstances. All investments involve risk, including loss of principal. Quantopian makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances.

I doesn't do very well in the last 2 years for some reason. I am going to tweak the parameters to try to take that bad 2013-2015 performance and make it better.

I haven't investigated, but I suspect that every other month, you are adjusting the hedge taking into account the previous month's new hedge?

All right, I figured it out.

I think the hedge stays in place now for the entirety of the backtest. Returns worsen, especially in recent years. The good news is that drawdown is further minimized and beta is brought close to 0 as well.

A smarter hedging strategy is probably needed and I'd have concerns about the performance over the last two years but a fun exercise.

Clone Algorithm
69
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: 5571c23d7cd037109412636f
There was a runtime error.

Great returns on your tweaks, Walter.

This is the same test as yours, except with picking the biggest losers instead of winners.

As you can see, the results are almost identical.

Clone Algorithm
41
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: 557254dc208aa710e93ed9d5
There was a runtime error.

Thanks for the ideas, guys. I found out that my screen is too restrictive and ends up with only like <20 stocks most periods. So the momentum ranking doesn't even do anything and the returns have actually all been from value. And I think this is part of the reason the performance since 2014 were bad - too few stocks to choose from. The bull market has lifted valuations and the only ones passing the screen are the dregs. I'm working on some changes to fix these issues.

Here are the results after I fixed the issue I mentioned. I changed the screen to do multiple sorts and cull the worst stocks, instead of just having static limits. I used some standard valuation ratios: EV/EBITDA, P/CF, P/E, P/FCF (P/B and P/S did not test well). This way we'll get the cheapest stocks but still have enough stocks to buy if valuations are higher than the limits. The performance improved a lot (and are frankly unbelievable), and returns are actually positive since 2014, matching the market's performance.

Some surprising things I found:
- Removing the momentum component improved the returns, even risk adjusted (by setting num_stock = num_screener_end).
- Removing the profitability filters improved returns (ROE and ROIC). I also tried to sort/cull by them, didn't help.

I still need to get the logging of leverage to work. For some reason it complains when I try to use record_leverage: "OrderSecurityOutsideUniverse: 0036 You have placed an order with an unexpected security: Security(2114 [DCO]). Please declare all securities in the initialize function by calling sid(123) for each security that will be used later in your algorithm."

I'm not sure if the strategy is using leverage or not. It's not supposed to but I suspect it might be, if it tries to close out a position but is not able to, while still opening new positions.

Also need to figure out how to use limit orders. I'm thinking some of these stocks are pretty illiquid and market orders would be risky.

And I want to try adding some logic to reduce drawdowns, maybe using a stoploss or shorting the index like Josh showed.

Clone Algorithm
187
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: 55762b43ce2b0e10e9a65a84
There was a runtime error.

Looks pretty sweet to me! What is the reason for the shares outstanding filter, just to target microcaps directly?

Thanks. That was just to screen out stocks that heavily dilute shareholders. I didn't know how to screen for growth in outstanding shares YOY or 3-year avg or something like that. It does exclude a lot of large-caps as an unfortunate side-effect, although I wasn't too worried since I'm guessing the best value stocks are usually small-caps.

Yeah, I'm just guessing that this universe is particularly microcap though. Point in time fundamentals data is coming soon I hear, then we'll be able to do these sorts of things. Still impressive!

The most recent code made $2,403,993 on max spent $385,345 (on 2011-11-22) for 624%.
Maybe see if you can find a common thread in some of the worst performers: CPA, CTCM, DYP, ENG, FSLR, MTEX, QCCO, SB, SKBI, SPP, TGIS among the 573 securiites traded.

Impressive results.

Throwing in half of spy is something generalizeable. Making the hedge too dynamic may not generalize too well and hence might fail in paper trade and in real life.

That's pretty amazing.

I'm a bit surprised that the turnover rate is necessarily set at every month even when you don't employ momentum. The fundamental filter doesn't work at all if you are to hold the portfolio for 1 year.

Since I'm a one trick pony, here's the same hedging strategy as above (half the portfolio value shorting SPY).

Clone Algorithm
25
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: 55764894f5478410dff9b598
There was a runtime error.

Here's a backtest with hedging and a tweak to the code to make it run a lot faster. Before, it was doing a query every day, now it's just once a month, so it runs like 30 times faster. For hedging, I hedged with IWM (small cap index) instead of SPY since it's more appropriate considering the stocks the screen is buying. Plus, IWM has underperformed SPY since 2014 so this hedge helps with that. One other idea: you can use a leveraged ETF like TNA as the hedge. This way you could keep your leverage at 1 but increase your exposure to the strategy.

Clone Algorithm
174
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: 557735aaf6d90a111a02b260
There was a runtime error.

thanks for sharing, walter. very interesting.

Walter,

Nice algo. The beta looks fantastic here. Why did you end up at a hedge ratio of .40?

Disclaimer

The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by Quantopian. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. No information contained herein should be regarded as a suggestion to engage in or refrain from any investment-related course of action as none of Quantopian nor any of its affiliates is undertaking to provide investment advice, act as an adviser to any plan or entity subject to the Employee Retirement Income Security Act of 1974, as amended, individual retirement account or individual retirement annuity, or give advice in a fiduciary capacity with respect to the materials presented herein. If you are an individual retirement or other investor, contact your financial advisor or other fiduciary unrelated to Quantopian about whether any given investment idea, strategy, product or service described herein may be appropriate for your circumstances. All investments involve risk, including loss of principal. Quantopian makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances.

Thanks. I just tried different numbers and that got the beta close to 0.

Will selling a couple thousand unowned IWM shares work in the real world to actually make money? Could you add shorting costs? Recently somewhere Simon says what some are.

At IB, IWM borrow cost is 1.0732% and SPY is 0.262%. Not too bad. But personally I'd just run the long-only version if I wanted to live trade this, since the returns are better and I'd want to run it in my Roth IRA to avoid taxes since the turnover is high, and IRAs can't short.

Great work!
I will be taking a deeper look into it soon.

The most recent algo shows 561%:
Profited 778048 on 377108 activated/transacted for PvR of only 206.3% barely beating the benchmark. Unfortunate.

Clone Algorithm
120
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: 569ed5f60510011103d94534
There was a runtime error.

So have you gotten any any real trading results?