Quantopian's community platform is shutting down. Please read this post for more information and download your code.
Back to Community
Beta to SPY

I worry I'm bordering on a dumb question here but how do we check our own algo's beta to SPY? Is this an option I'm not seeing somewhere?

Might have found it, is this just represented by 'beta' on the backtester? Also, maybe a better question is how do you go about making this value lower? I"m getting betas around ~4.

10 responses

I think it depends on what benchmark your backtest is using? The default should be SPY.

Edit: As far as the contest is concerned, I believe there is a specific timeframe for which the official beta is calculated.

Yes, so far, I just keep trying parameter and fund changes to get lower "Betas"...not very satisfying...

Well, this is what they actually say in the contest FAQ

Beta: How connected your algorithm is to swings in the value of SPY.
Closer to zero is better. Values between 0.3 and -0.3 will pass the
filter. We are computing your beta-to-SPY over a trailing 1-year
period at the end of each month for a year, and then averaging those
results.

but what is the mathematical formula or python code for this...
Is it a correlation coefficient over the last-of-the-month trailing 12 values for the benchmark and the contest prices??

Ok, I found a simple reference...
http://investexcel.net/calculate-stock-beta-with-excel/
now to see if I can get the python code to get the actual number occurring in the Leaderboard.

Perchance, is that calculation in Zipline? I haven't actually looked at that code yet.

according to zipline the code is this:

def estimateBeta(priceY,priceX):  
    algorithm_returns = (priceY/priceY.shift(1)-1).dropna().values  
    benchmark_returns = (priceX/priceX.shift(1)-1).dropna().values  
    if len(algorithm_returns) <> len(benchmark_returns):  
        minlen = min(len(algorithm_returns), len(benchmark_returns))  
        if minlen > 2:  
            algorithm_returns = algorithm_returns[-minlen:]  
            benchmark_returns = benchmark_returns[-minlen:]  
        else:  
            return 1.00  
    returns_matrix = np.vstack([algorithm_returns, benchmark_returns])  
    C = np.cov(returns_matrix, ddof=1)  
    algorithm_covariance = C[0][1]  
    benchmark_variance = C[1][1]  
    beta = algorithm_covariance / benchmark_variance

    return beta

Hi guys,

Great questions!

Alan - trial and error is definitely not your best bet :)

Rather than try to get into much complexity in a reply here I'll point you to a couple of awesome resources that Delaney has created on this topic. You can join a live webinar on this topic this Wednesday at noon ET(GMT+4), sign up here. Ahead of that you can check out this post with more info, an IPython notebook on how to compute Beta as well as some nice sample algos created by David Edwards.

Hope you find those resources helpful - and please come back with more questions as they come up!
Best, Jess

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.

Peter,
Thanks for the pointer to the code. That is perfect!

Jessica,
Thanks for the collateral . Together these should be enough to move on from parameter exploration!

alan

Could someone condense those into functions that can be dropped into an algo to obtain beta?
I think maybe the one above would need portfolio values in a timeseries dataframe for priceY.
And priceX could be something like prices_df[symbol('SPY')] coming from history().
Having the notebook beta elements extracted/simplified would be great too.
Plus then the lookback window to use, and maybe a consideration on which one is fastest.
Thanks.

This is what I do:

def initialize(context):  
    context.equity = Series()  
    context.benchmark = Series()  
    context.benchmarkSecurity = symbol('SPY')  
    set_benchmark(context.benchmarkSecurity)  
. . .
    schedule_function(func=T1559_closing_bookkeeping,  
                      date_rule=date_rules.every_day(),  
                      time_rule=time_rules.market_close(minutes=1),  
                      half_days=True  
                      )  
. . .
def T1559_closing_bookkeeping(context, data):  
    try:  
        record_equity(context, data)  
    except:  
        log.error("Exception while recording equity-based stats")  
. . .
def record_equity(context, data):  
    context.equity = context.equity.append(Series({get_datetime(): context.portfolio.portfolio_value}))  
    context.benchmark = context.benchmark.append(Series({get_datetime(): data[context.benchmarkSecurity].close_price}))  
    recordCorr(context)  
. . .
def recordCorr(context):  
    record( leverage=context.account.leverage )  
    span = 60.0  
    if (context.equity.size > span):  
        equityReturns = context.equity.pct_change()  
        benchmarkReturns = context.benchmark.pct_change()  
        benchVar = pd.stats.moments.ewmvar(benchmarkReturns, span=span)  
        cov = pd.stats.moments.ewmcov(equityReturns, benchmarkReturns, span=span)  
        record(emwv_3m_beta = cov.tail(1).item() / benchVar.tail(1).item())  
. . .    

That last function, you can replace with their beta calculation, instead of the exponentially-weighted version.

Hey Gary,

The algorithms David wrote in the post Jess mentioned also contain some code to compute beta to the market. In this case we compute the alphas and betas of all the assets held, after which we just need to take a dollar weighted average to get to the algorithm's beta to SPY.

def get_alphas_and_betas(context, data):  
    """  
    returns a dataframe of 'alpha' and 'beta' exposures  
    for each asset in the current universe.  
    """  
    prices = history(context.lookback, '1d', 'price', ffill=True)  
    returns = prices.pct_change()[1:]  
    index_returns = returns[context.index]  
    factors = {}  
    for asset in context.portfolio.positions:  
        try:  
            X = returns[asset]  
            factors[asset] = linreg(X, index_returns)  
        except:  
            log.warn("[Failed Beta Calculation] asset = %s"%asset.symbol)  
    return pd.DataFrame(factors, index=['alpha', 'beta'])  

Thanks,
Delaney

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 Simon, altho looks complicated.
Thanks Delaney, I see that several imports from the Notebook are needed and it won't run in the backtester due to matplotlib.

Is there an easier solution for the backtest environment? It would likely improve contest entries since beta is critical there.

Q: Consider populating a new variable:
context.portfolio.beta or context.metric.beta (the exact value we see above the chart, as it is already calculated anyway)

This code calculates and charts beta using three different inputs: returns, portfolio value, and positions value.
Adding 1 to returns was the key for returns and portfolio betas to match, credit Burrito Dan for pointing that out.

The 1.0 using positions value can look appealing however those numbers in various conditions can be huge.

Results for various inputs  
2010-06-30 to 2017-06-14  
10 shares of SPY where the price is $104.00 at start.  
(Margin of 818 with initial capital at 104).

Beta inputs:  
    ==> returns (the Quantopian method) or portfolio_value  
            cash            Quantopian beta         beta calculated  
                104         3.73                     3.74  
                1040         .97                      .98  
                10400        .13                      .13  
    ==> positions_value  
            cash            Quantopian beta         beta calculated  
                104         3.73                     1.0  
                1040         .97                     1.0  
                10400        .13                     1.0