Back to Community
Gold Long Short

Since the new Pipeline masking feature came out it has been possible to do some more complicated computations, including linear regression. This is a quick and dirty algorithm where I long stocks that have a low magnitude beta to gold prices, and short stocks that have a high magnitude beta to gold.

Enjoy!

Clone Algorithm
338
Loading...
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
from quantopian.algorithm import attach_pipeline, pipeline_output
from quantopian.pipeline import Pipeline
from quantopian.pipeline.data.builtin import USEquityPricing
from quantopian.pipeline.factors import CustomFactor, AverageDollarVolume
from quantopian.pipeline.data.quandl import bundesbank_bbk01_wt5511 as gold


import pandas as pd
import numpy as np
from scipy.stats import linregress

class QuandlLinearRegression(CustomFactor):
    
    outputs = ['alpha', 'beta', 'r_value', 'p_value', 'stderr'] 
    
    def compute(self, today, assets, out, benchmark, y):
        returns = np.diff(y, axis=0) / y[:-1]
        benchmark_values = benchmark[:,0]
        benchmark_returns = np.diff(benchmark_values) / benchmark_values[:-1]

        alpha = out.alpha
        beta = out.beta
        r_value = out.r_value
        p_value = out.p_value
        stderr = out.stderr
        for i in range(len(out)):
            other_asset = returns[:, i]
            regr_results = linregress(y=other_asset, x=benchmark_returns)
            # `linregress` returns its results in the following order:
            # slope, intercept, r-value, p-value, stderr
            alpha[i] = regr_results[1]
            beta[i] = regr_results[0]
            r_value[i] = regr_results[2]
            p_value[i] = regr_results[3]
            stderr[i] = regr_results[4]


# Put any initialization logic here.  The context object will be passed to
# the other methods in your algorithm.
def initialize(context):
    
    pipe = Pipeline()
    pipe = attach_pipeline(pipe, name='regression_metrics')
    
    dollar_volume = AverageDollarVolume(window_length=20)
    high_dollar_volume = (dollar_volume > 10**7)
    
    data_regression_results = QuandlLinearRegression(inputs=[gold.value, USEquityPricing.close],
                                                              window_length=60, 
                                                              mask=high_dollar_volume)
    
    beta = data_regression_results.beta
    
    pipe.add(beta, "gold_beta")
    
    pipe.set_screen(high_dollar_volume)
    
    context.shorts = None
    context.longs = None
    
    schedule_function(plot, date_rules.every_day())
    schedule_function(rebalance, date_rules.month_start())
    
def before_trading_start(context, data):
    results = pipeline_output('regression_metrics').dropna()      
    ranks = results["gold_beta"].abs().order()
    
    context.shorts = ranks.tail(50)
    context.longs = ranks.head(50)
    

# Will be called on every trade event for the securities you specify. 
def handle_data(context, data):
    pass

def plot(context, data):
    record(lever=context.account.leverage,
           exposure=context.account.net_leverage,
           num_pos=len(context.portfolio.positions),
           oo=len(get_open_orders()))

        
    
def rebalance(context, data):
    for security in context.shorts.index:
        if get_open_orders(security):
            continue
        order_target_percent(security, -0.5 / len(context.shorts))
            
    for security in context.longs.index:
        if get_open_orders(security):
            continue
        order_target_percent(security, 0.5 / len(context.longs))
            
    for security in context.portfolio.positions:
        if get_open_orders(security):
            continue
        if security not in (context.longs.index | context.shorts.index):
            order_target_percent(security, 0)
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.

7 responses

Very interesting idea.

Here's a tearsheet of the algo, drawdown is high in the 09 era (not surprising) and seems to improve thereafterwards.

Loading notebook preview...
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.

Great!

I am curious as to how I can swap out regressing against gold for SPY for example. Or are you limited here to Quandl data?

take a look at the just released correlation and regression factors where you can regress against SPY, or any dataset of the proper form.

https://www.quantopian.com/posts/new-pipeline-features-slicing-and-correlation-slash-regression-methods

Really useful code! I'm Confused why the loop is in that custom factor? It obviously works, but I understood that pipeline performs the calc for each stock each day - so why is this separately looping through stocks?

I wrote this algo before the new regression with datasets functionality was added, so i had to hack someparts.

Here is the post about the new regression factor methods https://www.quantopian.com/posts/new-pipeline-features-slicing-and-correlation-slash-regression-methods

Post back here when you update it, I'd like to see the much cleaner code.

Unfortunately, the regression factor methods are too limited for anything I'm trying to do. E.g only one variable and cant alter estimation methods.

The statsmodels .fit functions still results in a misaligned matrix error without the loop. But the loop seems to make it extremely slow. So I'm currently testing if I can make it usable by performing regressions outside a pipeline and taking top/bottom rankings.
Cheers.

Fair point on the estimation methods. You may want to consider looking at the implementation in zipline and try your own implementation replacing scipy.stats.linregress with sklearn.linear_models...