Back to Community
Common returns seem to be out of reach

My problem is that the accompanying strategy trades only sector ETFs used in Quantopian's Sector Exposures. So, the Common Return portion of the backtest should be very close to the actual results (less trading impact). On the contrary, returns for this strategy were -7.34% over the course of 2017, while "Common Returns" during that period were +65.73%. Appreciate any help, thanks.

Clone Algorithm
7
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
"""
PHOENIX
"""
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 AverageDollarVolume
from quantopian.pipeline.data import morningstar
from quantopian.pipeline.filters.morningstar import IsPrimaryShare
from quantopian.pipeline.filters import Q1500US
import operator # for sorting

from quantopian.pipeline.experimental import risk_loading_pipeline


def initialize(context):
    """
    Called once at the start of the algorithm.
    """
    #Slippage

    # Default
#    set_commission(commission.PerShare(cost=0.0075, min_trade_cost=1))
#    set_slippage(slippage.VolumeShareSlippage(volume_limit=0.025, price_impact=0.1))
    # Franky best bet
    set_commission(commission.PerShare(cost=0.0075, min_trade_cost=1))
    set_slippage(slippage.FixedSlippage(spread=0.02))
    # no cost of trading
#    set_commission(commission.PerShare(cost=0, min_trade_cost=0))
#    set_slippage(slippage.FixedSlippage(spread=0))

# moved the leverage stuff down
#    context.long_leverage = 0.8
#    context.short_leverage = -0.8

    # Rebalance every day, 1 hour after market open.
    schedule_function(my_rebalance, date_rules.every_day(), time_rules.market_close(minutes=10))
     
    # Record tracking variables at the end of each day.
    schedule_function(my_record_vars, date_rules.every_day(), time_rules.market_close())
     
    # Create our dynamic stock selector.
    attach_pipeline(make_pipeline(), 'my_pipeline')
    
    # Attach the pipeline for the risk model factors that we
    # want to neutralize in the optimization step. The 'risk_factors' string is 
    # used to retrieve the output of the pipeline in before_trading_start below.
    attach_pipeline(risk_loading_pipeline(), 'risk_factors')

    
def make_pipeline():

    # Filter for primary share equities. IsPrimaryShare is a built-in filter.
    primary_share = IsPrimaryShare()

    # Equities listed as common stock (as opposed to, say, preferred stock).
    # 'ST00000001' indicates common stock.
    common_stock = morningstar.share_class_reference.security_type.latest.eq('ST00000001')

    # Non-depositary receipts. Recall that the ~ operator inverts filters,
    # turning Trues into Falses and vice versa
    not_depositary = ~morningstar.share_class_reference.is_depositary_receipt.latest

    # Equities not trading over-the-counter.
    not_otc = ~morningstar.share_class_reference.exchange_id.latest.startswith('OTC')

    # Not when-issued equities.
    not_wi = ~morningstar.share_class_reference.symbol.latest.endswith('.WI')

    # Equities without LP in their name, .matches does a match using a regular
    # expression
    not_lp_name = ~morningstar.company_reference.standard_name.latest.matches('.* L[. ]?P.?$')

    # Equities with a null value in the limited_partnership Morningstar
    # fundamental field.
    not_lp_balance_sheet = morningstar.balance_sheet.limited_partnership.latest.isnull()

    # Equities whose most recent Morningstar market cap is not null have
    # fundamental data and therefore are not ETFs.
    have_market_cap = morningstar.valuation.market_cap.latest.notnull()

    # create the price and volume variables
    # use them to filter the universe further
    price = USEquityPricing.close.latest
    above_min_price = price > 5
    
    volume = USEquityPricing.volume.latest
    above_min_volume = volume > 500000
    
    # Filter for stocks that pass all of our previous filters.
    my_universe = (
        primary_share
        & common_stock
        & not_depositary
        & not_otc
        & not_wi
        & not_lp_name
        & not_lp_balance_sheet
        & have_market_cap
        & above_min_price
        & above_min_volume
    )

    pipe = Pipeline(
        columns = {
            'price': price,
            'volume': volume,
        },
#        screen = Q1500US() & above_min_price & above_min_volume
        screen = (my_universe),
    )
    return pipe

def before_trading_start(context, data):
    context.output = pipeline_output('my_pipeline')
    context.security_list = context.output.index
    
    # how big is our universe?
    print context.output.count()
    # check for individual security in overall security_list, if you want to ...
    # print symbol('UVE') in context.security_list

    # This dataframe will contain all of our risk loadings
    context.risk_loadings = pipeline_output('risk_factors')
    
def my_assign_weights(context, data):
    """
    Assign weights to securities that we want to order.
    """
    pass
 
def my_rebalance(context,data):

    risk_loadings = context.risk_loadings

    numBars = 6
    price_history = data.history(context.security_list, ["price", "volume"], bar_count=numBars, frequency="1d")
        
    fBuys = {}
    fSells = {}
    for s in context.security_list:
        avgPerf = price_history["price"][s].pct_change().mean()
        fPerfSignal = price_history["price"][s].pct_change().mean() / (price_history["price"][s].pct_change().std() + .0000000001)
        fVolSignal = price_history["volume"][s].iloc[-1] / price_history["volume"][s].iloc[1:].mean()
        if fPerfSignal < -1 and fVolSignal > 1.5:
            try:
                print risk_loadings.loc[s]
                print avgPerf
                fBuys[s] = avgPerf
            except:
                print s
                print " potential Buy, but had no factors available"

        if fPerfSignal > 1 and fVolSignal > 1.5:
            try:
                print risk_loadings.loc[s]
                print avgPerf
                fSells[s] = avgPerf
            except:
                print s
                print " potential Sell, but had no factors available"
    
    # work with the Buy ideas
    print 'fBuys (count of ' + str(len(fBuys)) + ')'
    numBuys = len(fBuys)
    print (fBuys)
    if len(fBuys) > 3:
        numBuys = 4
    else:
        numBuys = len(fBuys)
    
    # work with the Sell ideas
    print 'fSells (count of ' + str(len(fSells)) + ')'
    numSells = len(fSells)
    print (fSells)
    if len(fSells) > 3:
        numSells = 4
    else:
        numSells = len(fSells)

    # Figure out leverage
    if numBuys == 0:
        short_leverage = -1.6
    else:
        short_leverage = -0.8
    if numSells == 0:
        long_leverage = 1.6
    else:
        long_leverage = 0.8

    # create etf_positions as a dictionary
    etf_positions = {}
    etf_positions["basic_materials"] = 0.0
    etf_positions["communication_services"] = 0.0
    etf_positions["consumer_cyclical"] = 0.0
    etf_positions["consumer_defensive"] = 0.0
    etf_positions["energy"] = 0.0
    etf_positions["financial_services"] = 0.0
    etf_positions["health_care"] = 0.0
    etf_positions["industrials"] = 0.0
    etf_positions["real_estate"] = 0.0
    etf_positions["technology"] = 0.0
    etf_positions["utilities"] = 0.0
    
    print etf_positions
    
    # LONG positions
    # couple ways to weight these:
    long_percentage = long_leverage * (1/(numBuys+.0000001))
    if long_percentage > 0.4: long_percentage = 0.4 # max weight 40%
    #if long_percentage > .2: long_percentage = .2 # max weight 20%
    
    # Sort the potential buys by avg performance, take the top four as our long list
    sorted_fBuys = sorted(fBuys.items(), key=operator.itemgetter(1))
    long_list = [i[0] for i in sorted_fBuys[:4]]
    print long_list

    # add the longs
    for x in range(0, numBuys):
        for key in etf_positions:
            if (risk_loadings.loc[long_list[x]][key] > 0):
                etf_positions[key] += long_percentage

    # SHORT positions
    # couple ways to weight these:
    short_percentage = short_leverage * (1/(numSells+.0000001))
    if short_percentage < -0.4: short_percentage = -0.4 # max weight -40%
    #if short_percentage < -0.2: long_percentage = -0.2 # max weight -20%

    # Sort the potential sells by reversed avg performance, take the top four as our short list
    sorted_fSells = sorted(fSells.items(), key=operator.itemgetter(1), reverse=True)
    short_list = [i[0] for i in sorted_fSells[:4]]
    print short_list

    # add the shorts
    for x in range(0, numSells):
        for key in etf_positions:
            if (risk_loadings.loc[short_list[x]][key] > 0):
                etf_positions[key] += short_percentage
    
    # trade the opposites of Franky
    for key in etf_positions:
        etf_positions[key] = -1.0 * etf_positions[key]

    print etf_positions
        
    # trade
    order_target_percent(symbol('XLB'), etf_positions["basic_materials"])
    order_target_percent(symbol('IYZ'), etf_positions["communication_services"])
    order_target_percent(symbol('XLY'), etf_positions["consumer_cyclical"])
    order_target_percent(symbol('XLP'), etf_positions["consumer_defensive"])
    order_target_percent(symbol('XLE'), etf_positions["energy"])
    order_target_percent(symbol('XLF'), etf_positions["financial_services"])
    order_target_percent(symbol('XLV'), etf_positions["health_care"])
    order_target_percent(symbol('XLI'), etf_positions["industrials"])
    order_target_percent(symbol('IYR'), etf_positions["real_estate"])
    order_target_percent(symbol('XLK'), etf_positions["technology"])
    order_target_percent(symbol('XLU'), etf_positions["utilities"])
        
        
def my_record_vars(context, data):
    """
    This function is called at the end of each day and plots certain variables.
    Also prints summary info to log
    """
    longs = shorts = 0
    long_symbols = short_symbols = ''
    account_net_liquidation = context.account.net_liquidation
    
    for position in context.portfolio.positions.itervalues():
        if position.amount > 0:
            percentage_value = (position.amount * position.last_sale_price) / account_net_liquidation
            if len(long_symbols) > 0:
                long_symbols = long_symbols + ", "
            long_symbols = long_symbols + position.sid.symbol + ' {:.0%}'.format(percentage_value)
            longs += 1
            
        if position.amount < 0:
            percentage_value = (position.amount * position.last_sale_price) / account_net_liquidation
            if len(short_symbols) > 0:
                short_symbols = short_symbols + ", "
            short_symbols = short_symbols + position.sid.symbol + ' {:.0%}'.format(percentage_value)
            shorts += 1

    # Record and plot the leverage of our portfolio over time as well as the
    # number of long and short positions. Even in minute mode, only the end-of-day
    # leverage is plotted.
    record(leverage = context.account.leverage, long_count=longs, short_count=shorts)

    # log the long and short names
    log.info("Today's longs: " + long_symbols)
    log.info("Today's shorts: " + short_symbols)
    
def handle_data(context,data):
    """
    Called every minute.
    """
    pass
There was a runtime error.
2 responses

Well, maybe trading impact is the difference. Here is a backtest that simply switches back and forth between the sectors and the S&P 500 every day. 59% impact.

Clone Algorithm
10
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
"""
Sector ETFs

"""

def initialize(context):

    set_commission(commission.PerShare(cost=0.0075, min_trade_cost=0))
    set_slippage(slippage.FixedSlippage(spread=0.2))

    # Rebalance at the end of the day
    schedule_function(rebalance,
                      date_rules.every_day(),
                      time_rules.market_close(minutes=10))
    
def rebalance(context,data):
    
    """
    order_target_percent(symbol('XLB'), .09)
    order_target_percent(symbol('IYZ'), .09)
    order_target_percent(symbol('XLY'), .09)
    order_target_percent(symbol('XLP'), .09)
    order_target_percent(symbol('XLE'), .09)
    order_target_percent(symbol('XLF'), .09)
    order_target_percent(symbol('XLV'), .09)
    order_target_percent(symbol('XLI'), .09)
    order_target_percent(symbol('IYR'), .09)
    order_target_percent(symbol('XLK'), .09)
    order_target_percent(symbol('XLU'), .09)
    """

    if len (context.portfolio.positions) < 5:
        order_target_percent(symbol('SPY'), 0)
        order_target_percent(symbol('XLB'), .09)
        order_target_percent(symbol('IYZ'), .09)
        order_target_percent(symbol('XLY'), .09)
        order_target_percent(symbol('XLP'), .09)
        order_target_percent(symbol('XLE'), .09)
        order_target_percent(symbol('XLF'), .09)
        order_target_percent(symbol('XLV'), .09)
        order_target_percent(symbol('XLI'), .09)
        order_target_percent(symbol('IYR'), .09)
        order_target_percent(symbol('XLK'), .09)
        order_target_percent(symbol('XLU'), .09)
    else:
        order_target_percent(symbol('SPY'), .99)
        order_target_percent(symbol('XLB'), 0)
        order_target_percent(symbol('IYZ'), 0)
        order_target_percent(symbol('XLY'), 0)
        order_target_percent(symbol('XLP'), 0)
        order_target_percent(symbol('XLE'), 0)
        order_target_percent(symbol('XLF'), 0)
        order_target_percent(symbol('XLV'), 0)
        order_target_percent(symbol('XLI'), 0)
        order_target_percent(symbol('IYR'), 0)
        order_target_percent(symbol('XLK'), 0)
        order_target_percent(symbol('XLU'), 0)
        
    print len (context.portfolio.positions)
There was a runtime error.

Looks like you should flip your long and shorts and will have a very good strategy