Back to Community
Long Only Strategy: allocate between bull and bear market portfolios

Overview
A long only strategy for the long haul. It contains two evenly weighted, independent portfolios.
1. A bull market portfolio of sector ETFs equivalent to the industries portfolio
2. A Bear market portfolio of bond ETFs

Details
In order to decide on an allocation between the two portfolios, the algorithm uses the returns on the bull market portfolio. It looks at several trailing windows of returns, for each window with a negative return, it weights towards the bear portfolio, and for each positive return, it weights towards the bull market portfolio. This has the effect of shifting into safer investments when the riskier ones become less profitable.

The algorithm is rebalanced every 20 business days, Interactive Brokers imposes a $10 minimum monthly commission, so we might as well get a rebalance in.

Clone Algorithm
455
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: 5384f2e8116ea00713fc72aa
There was a runtime error.
12 responses

This is the same algorithm with the context variable 'allow_additional_leverage' set to True. In this case, when the confidence on the returns is high, it will borrow additional money on a margin.

Clone Algorithm
455
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: 5384f3335b20a30712e6d2c0
There was a runtime error.

Very neat David, thank you for sharing.

Hi David,

Looking at your return chart (initial post, no borrowing), the algo manages to avoid the major downturn of the "Great Recession" but otherwise tracks the market. Other than borrowing to amplify the bull market, is there any way the algo could be modified to improve the return after the 2008-2009 crash?

Grant

Grant, here's something you could try: short the bull portfolio instead of putting into bear.

I'm going to give that a try, but looking at another algo first...

Grant,
I'd say Jason is correct that you could try using the signal to move into short positions, but I am always a little skeptical of returns on short algos through that time period because it was not always easy to short.

Other things you could do would be to mess with the window lengths, maybe weight the more recent windows higher than the longer ones. That might make it more responsive to market movements, but it is likely to incur more trade costs.

To improve the post '09 returns, other than borrowing more, there is not much you can do with this as is. This version uses an even weighting when it rebalances, but another rebalance method might improve the returns.

My thought process here was to use fundamental investing principles involving stocks and bonds. I wanted it to have a high capital capacity, and be simple enough for the average investor to understand what it's doing.

Hi,

I am livetrading this one with real money.

Should this not be in to avoid buying and buying as you stated in a different post to another algo?

J.

    #if open orders wait till there are executed.  
    # skip tic if any orders are open or any stocks did not trade  
    for stock in context.stocks:  
        if bool(get_open_orders(stock)) or data[stock].datetime < get_datetime():  
            return  

Another question about increasing account balance: https://www.quantopian.com/posts/what-is-effect-of-increasing-account-balance-of-a-real-money-live-trading-account.
I suggest to stop algo and redeploy so it synchronizes the open orders again?

Hi J,
Glad to hear you're trading this algo, I really like the concept. I have some other variations on the idea that I can share as well. The check for open orders is not a big issue for this algorithm because it is lower frequency in nature. All open orders are cancelled at the end of the trading day by default, and this algorithm will trade at most once per day, so you shouldn't run into open orders when it comes time to rebalance.

Depending on the securities and amount of capital you are using, the only possible issue I could see would be if an order did not fill completely by the end of the trading day. You could calculate the target number of shares at rebalance, and order the difference the following day if any orders did not completely fill. The odds of this are pretty low if you are using the ETFs or highly liquid stocks.

Here's a function to convert percents to target position sizes.

def targets_from_weights(context, W):  
    """  
    context: obj  
        contains current portfolio state  
    W: pandas Series  
        target weights vector indexed by sid.

    returns: Series  
        target position sizes required to achieve target weights.  
    """  
    equity = context.portfolio.portfolio_value  
    current_prices = history(1, '1d', 'price').iloc[-1] # .iloc is just to convert the DataFrame to a Series, there is only one row.  
    # Use floor division to get whole shares  
    return (W * equity) // current_prices  

As for increasing the capital in the account, I'd say you have the right idea, you can just deposit the money and it will use the new capital at the next rebalance, or you can kill it and redeploy to get that cash in the market faster. Also note that the days between rebalance is the number of trading days, not calendar days.

Good to have you live trading, feel free to message me if you have any questions.

David

Thanks for sharing this. I tried a few different rebalance days, looks like 14 days gives a slightly better returns with similar increase in drawdown. Just wanted to share if someone is interested.

Jay

btw: 'allow_additional_leverage' set to True

Clone Algorithm
63
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: 53c900d5d08bde074bed448c
There was a runtime error.

Thanks for sharing this. I am new to Q and am trying to run this algorithm but I get this error.

AssertionError: Number of Block dimensions (1) must equal number of axes (2)
There was a runtime error on line 216.

Any help is greatly appreciated.

Thanks.

I've updated the algorithm to use the supported schedule_function instead of the original author's custom EventManager so it works again. It now trades every month instead of every 20 business days - but the functionality is mostly the same.

Check out the backtest up to October of 2016!

Let me know if you have any questions

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: 57ffb624fa48901057428f1e
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.

Thanks a lot Matthew. I tried it just now and it works!

I got a warning from line 91 about history() being deprecated soon and that we need to use data.history instead. Its a minor thing, but probably worth pointing it out to make this algorithm future-proof.