Back to Community
Stock-Bond Balance

The latest year Quantopian staff pushing crowd to create Long-Short portfolios to neutralize beta.
But there are many other ways to reach low beta. One of them Stock-Bond Balance.
I am happy that I am not the only in this community who prefer Balanced portfolios.

Happy New Year to All!!!

Clone Algorithm
137
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
# Stock-Bond balance control by sum of returns 
# https://www.quantopian.com/posts/slope-calculation#568533eaf47dab4dc500016b

def initialize(context): 
    
    context.stock = symbol('SPY')  
    context.bond = symbol('TLT') 
    schedule_function(trade, date_rules.week_end(days_offset=0),  time_rules.market_close(minutes=15)) 
    
def trade(context, data):
    
    stock = context.stock
    bond = context.bond 
    period = 70
    target_lev = 1.00

    prices = history(period+1, '1d', 'price')[0:-1]
    ret_sum = prices.pct_change().sum()
    
    r_diff = ret_sum[stock] - ret_sum[bond]
    r_sum = abs(ret_sum[stock]) + abs(ret_sum[bond])
    r_diff_norm = r_diff/r_sum
    
    record(r_diff = r_diff)
    record(r_diff_norm = r_diff_norm)
    
    wt_stock = target_lev*(1.00+r_diff_norm)*0.50
    wt_bond = target_lev*(1.00-r_diff_norm)*0.50
    
    order_target_percent(stock, wt_stock)
    order_target_percent(bond, wt_bond)    
    
def handle_data(context, data):
    record(Leverage = context.account.leverage) 
    
'''
    week_end(days_offset=0)
    period = 70
    target_lev = 1.00


Total Returns
190.6%
Benchmark Returns
73.4%
Alpha
0.19
Beta
0.04
Sharpe
1.32
Sortino
1.86
Information Ratio
0.91
Volatility
0.14
Max Drawdown
20%


'''
There was a runtime error.
21 responses

Awesome! I was literally just looking for this! Are there any other bonds (such as different maturity lengths) available?

Alexander
You may find them here.

Here's the algo run over the past year. It takes a pretty big hit right at the end, resulting in a max drawdown of 10% over the year.

By the way, my little doodle was inspired by Market Tech's post on https://www.quantopian.com/posts/slope-calculation, since we are crediting sources.

Clone Algorithm
1
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
# Stock-Bond balance control by sum of returns 
# https://www.quantopian.com/posts/slope-calculation#568533eaf47dab4dc500016b

def initialize(context): 
    
    context.stock = symbol('SPY')  
    context.bond = symbol('TLT') 
    schedule_function(trade, date_rules.week_end(days_offset=0),  time_rules.market_close(minutes=15)) 
    
def trade(context, data):
    
    stock = context.stock
    bond = context.bond 
    period = 70
    target_lev = 1.00

    prices = history(period+1, '1d', 'price')[0:-1]
    ret_sum = prices.pct_change().sum()
    
    r_diff = ret_sum[stock] - ret_sum[bond]
    r_sum = abs(ret_sum[stock]) + abs(ret_sum[bond])
    r_diff_norm = r_diff/r_sum
    
    record(r_diff = r_diff)
    record(r_diff_norm = r_diff_norm)
    
    wt_stock = target_lev*(1.00+r_diff_norm)*0.50
    wt_bond = target_lev*(1.00-r_diff_norm)*0.50
    
    order_target_percent(stock, wt_stock)
    order_target_percent(bond, wt_bond)    
    
def handle_data(context, data):
    record(Leverage = context.account.leverage) 
    
'''
    week_end(days_offset=0)
    period = 70
    target_lev = 1.00


Total Returns
190.6%
Benchmark Returns
73.4%
Alpha
0.19
Beta
0.04
Sharpe
1.32
Sortino
1.86
Information Ratio
0.91
Volatility
0.14
Max Drawdown
20%


'''
There was a runtime error.

@Alexander- Here are some bond ETFs.

  • iShares: AGG TLT TLH SHY SHV IEF IEI HYG LQD
  • SPDR: JNK
  • Vanguard: BND VGLT VGSH VCLT VCSH VMBS EDV

See also

@Andre

Awesome! This helps a lot.

Cheers!

@Alexander- Try this algorithm from half a year ago. Some ETFs produce runtime errors Quantopian doesnt care to explain - probably because they were created after the backtest start date.

Clone Algorithm
1
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
# BuyHoldBonds150628M, from BuyHoldTreasuryBonds150531Su - Buys and holds a bond ETF, buys more on receiving dividends. 2?40p-310p
def initialize(context):
    #context.secu=symbol('TLT') # iShares 20+ Year Treasury Bond ETF
    #*context.secu=symbol('HYG') # iShares Trust - iShares iBoxx $ High Yield Corporate Bond ETF
    #* unspecified runtime errors, "something went wrong"
    #context.secu=symbol('AGG') # iShares Trust - iShares Core U.S. Aggregate Bond ETF
    context.secu=symbol('LQD') # iShares Trust - iShares iBoxx $ Investment Grade Corporate Bond ETF
    #context.secu=symbol('JNK') # SPDR Series Trust - SPDR Barclays High Yield Bond ETF
    #*context.secu=symbol('BND') # Vanguard Bond Index Funds - Vanguard Total Bond Market ETF
    #context.secu=symbol('IEF') # iShares Trust - iShares 7-10 Year Treasury Bond ETF
    #context.secu=symbol('SHY') # iShares Trust - iShares 1-3 Year Treasury Bond ETF
    #context.secu=symbol('SHV') # iShares Trust - iShares Short Treasury Bond ETF
    log.info('Trading {} ({})'.format(context.secu.security_name.title()
                                      #.capitalize()
                                      , context.secu.symbol))
    #context.portfolio.cash=1e5 # $100,000 - default
    #se#t_commission_(commission.PerShare(0.03, None)) # default

# Will be called on every trade event for the securities you specify. 
def handle_data(context, data):
    p=data[context.secu].price
    c=0.03 # commission in USD/share
    n=context.portfolio.cash/(p+c)
    if 1:
        n=int(n)
    if n: 
        order(context.secu, n)
        log.info('{}: Ordered {n}*{sym}@${p}'.format(get_datetime().time(), n=n, sym=context.secu.symbol, p=p))
There was a runtime error.

Migrated to Q2 version out of sample results:
From 2015-12-30 to 2016-07-01

Total Returns
13.2%
Benchmark Returns
2.2%
Alpha
0.24
Beta
0.05
Sharpe
3.27
Sortino
4.94
Information Ratio
2.88
Volatility
0.07
Max Drawdown
3.1%

Clone Algorithm
137
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
# Stock-Bond balance !!!   

def initialize(context): 
    
    context.assets =symbols('XLP','TLT')
    schedule_function(trade, date_rules.week_end(days_offset=0),  time_rules.market_close(minutes=15)) 
    
def trade(context, data):
    
    stock = context.assets[0]
    bond = context.assets[1]
    period = 70
    target_lev = 1.00
    pw = 0.5

    prices = data.history(context.assets, 'price', period+1, '1d')[0:-1]
    ret_sum = prices.pct_change().sum()
    
    r_diff = ret_sum[stock] - ret_sum[bond]
    # record(r_diff = r_diff)
    if r_diff>0.0:        
        adpt = (1+r_diff)**pw-1.0
    elif r_diff<0.0:    
        adpt =-((1+abs(r_diff))**pw-1.0)
    else:    
        adpt =0.0   
  
    wt_stock = target_lev*(0.50+adpt)
    wt_bond = target_lev*(0.50-adpt)

    order_target_percent(stock, wt_stock)
    order_target_percent(bond, wt_bond) 
    
    record(wt_stock = wt_stock, wt_bond = wt_bond)

    record(Leverage = context.account.leverage) 
    
'''
    week_end(days_offset=0)
    period = 70
    target_lev = 1.00


Total Returns
190.6%
Benchmark Returns
73.4%
Alpha
0.19
Beta
0.04
Sharpe
1.32
Sortino
1.86
Information Ratio
0.91
Volatility
0.14
Max Drawdown
20%


'''
There was a runtime error.

Any Idea on how to apply this with results from pipeline? Cant figure out how to implement so far I have...

def before_trading_start(context, data):
context.data = pipeline_output('my_pipeline').dropna()

context.data_sort = context.data.sort(['eps_growth'], ascending=False).iloc[:200]  


context.final_longs_sort = context.data_sort.sort(['dollar_volume'], ascending=False).iloc[:100]  

context.long_final = context.final_longs_sort  

context.security_list = context.long_final.index  

context.hedge = symbol('TLT')  


log.info(context.long_final)  

def rebalance(context, data):

stock = context.security_list  
bond = context.hedge  
period = 70  
target_lev = 1.00  
pw = 0.5

price_hedge = data.history(context.hedge, 'price', period+1, '1d')[0:-1]  
ret_sum1 = price_hedge.pct_change().sum()  

prices = data.history(context.long_final.index, 'price', period+1, '1d')[0:-1]  
ret_sum2 = prices.pct_change().sum()  


r_diff = ret_sum2[stock] - ret_sum1[bond]  
#record(r_diff = r_diff)  
if r_diff>0.0:  
    adpt = (1+r_diff)**pw-1.0  
elif r_diff<0.0:  
    adpt =-((1+abs(r_diff))**pw-1.0)  
else:  
    adpt =0.0  

wt_stock = target_lev*(0.50+adpt)  
wt_bond = target_lev*(0.50-adpt)

order_target_percent(stock, wt_stock)  
order_target_percent(bond, wt_bond)  

record(wt_stock = wt_stock, wt_bond = wt_bond)

record(Leverage = context.account.leverage)  

This is the error I'm getting when I try to implement in my algo. Im new to quantopian and python so not sure what I'm doing wrong here. What should I do?

TypeError: 'float' object has no attribute '__getitem__'
... USER ALGORITHM:122, in rebalance
r_diff = ret_sum2[stock] - ret_sum1[bond]

I think your ret_sum1 is a scalar of type float, and so you can't index it with [bond]. Remove this part.

Also, you probably want the sum of all stock returns, which would be ret_sum2[stock].sum(). Does this work?

Add a line to print r_diff. It should be a float scalar, or you'll get errors in the if statement that follows.

Awesome Thanks André! I will give it a go . Should I remove the whole ret_sum1 or just the [bond] part?

I think that worked André. However, now I get UnsupportedOrderParameters: Passing non-Asset argument to 'order()' is not supported. Use 'sid()' or 'symbol()' methods to look up an Asset.
There was a runtime error on line 135.

This is how its looking now

stock = context.security_list
bond = context.hedge
period = 70
target_lev = 1.00
pw = 0.5

price_hedge = data.history(context.hedge, 'price', period+1, '1d')[0:-1]  
ret_sum1 = price_hedge.pct_change().sum()  

prices = data.history(context.long_final.index, 'price', period+1, '1d')[0:-1]  
ret_sum2 = prices.pct_change().sum()  


r_diff = ret_sum2[stock].sum() - ret_sum1  
if r_diff>0.0:  
    adpt = (1+r_diff)**pw-1.0  
elif r_diff<0.0:  
    adpt =-((1+abs(r_diff))**pw-1.0)  
else:  
    adpt =0.0  

wt_stock = target_lev*(0.50+adpt)  
wt_bond = target_lev*(0.50-adpt)

order_target_percent(stock, wt_stock)  
order_target_percent(bond, wt_bond)  

record(wt_stock = wt_stock, wt_bond = wt_bond)

record(Leverage = context.account.leverage)  

That's because your stock is not a single Asset like your bond, but a list. You have to write a loop over stock, which would order some portion of wt_stock, eg. wt_stock/len(stock), for each individual security.

Hi André check it out. Im posting the backtest with the suggested changes. Theres a couple of things Im having trouble with, for some reason the leverage is really high and then I get a KeyError: 'the label [2016-05-12 00:00:00+00:00] is not in the [index]'
There was a runtime error on line 83.
Before merging my algo with this one, I was not getting any leverage and had no problems. Im wondering if I'm doing something wrong in compute weights and the rebalance. Sorry for the messy code, I'm still trying to figure things out as a newb!

Clone Algorithm
1
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
from quantopian.algorithm import attach_pipeline, pipeline_output  
from quantopian.pipeline import Pipeline  
from quantopian.pipeline.data.builtin import USEquityPricing  
from quantopian.pipeline.data import morningstar
from quantopian.pipeline.factors import SimpleMovingAverage, AverageDollarVolume, CustomFactor, Returns
from quantopian.pipeline.data.psychsignal import stocktwits

from quantopian.pipeline.data.estimize import (
    consensus_estimize_eps,
    consensus_wallstreet_eps,
    consensus_estimize_revenue, 
    consensus_wallstreet_revenue,
    ConsensusEstimizeEPS,
    ConsensusWallstreetEPS,
    ConsensusEstimizeRevenue, 
    ConsensusWallstreetRevenue
)

class Surprise(CustomFactor):
    window_length = 20
    inputs = [ConsensusEstimizeEPS.previous_actual_value,
              ConsensusEstimizeEPS.previous_mean]

    def compute(self, today, assets, out, actual_eps, estimize_eps):
        out[:] = (actual_eps[-1] - estimize_eps[-1])/(estimize_eps[-1] + 0)
       
        
def initialize(context):  
    attach_pipeline(my_pipeline(context), 'my_pipeline')  
    
    schedule_function(rebalance, 
                      date_rules.week_end(days_offset=0),
                      time_rules.market_open(hours = 0, minutes = 30))
                      
    
    set_slippage(slippage.FixedSlippage(spread=0.00))
    set_commission(commission.PerTrade(cost=1.00))
                    
    #context.my_leverage = 0.99
    

def my_pipeline(context):
    
    recent_returns = Returns(window_length=20)
    
    return Pipeline(  
        columns={  
           
            'close': USEquityPricing.close.latest,
            'dollar_volume': AverageDollarVolume(window_length=20), 
            'rec_returns' : recent_returns,
            'pct_surp': Surprise (),
            'rev_growth': morningstar.operation_ratios.revenue_growth.latest,
            'eps_growth' : morningstar.earnings_ratios.diluted_eps_growth.latest,
            'total_bullish' : stocktwits.bull_scored_messages .latest,
            'eps_est': consensus_estimize_eps.estimize_eps_final.latest,
            'actual_eps': ConsensusEstimizeEPS.previous_actual_value.latest,
            'num_est': consensus_estimize_eps.count.latest,
            'roe'  : morningstar.operation_ratios.roe.latest,
            'pe' : morningstar.valuation_ratios.pe_ratio.latest,
            'mkt_cap' : morningstar.valuation.market_cap.latest,
            '50d' : SimpleMovingAverage(inputs=[USEquityPricing.close], window_length=50),
            'roe_pe' : ((morningstar.operation_ratios.roe.latest / morningstar.valuation_ratios.pe_ratio.latest)*100)*4,  
            'ws_eps' : consensus_wallstreet_eps.wallstreet_eps_final.latest,
            'ws_rev' : consensus_wallstreet_revenue.wallstreet_revenue_final.latest,
            'es_rev' : consensus_estimize_revenue.estimize_revenue_final.latest,
            'rev_rank' : ((consensus_estimize_revenue.estimize_revenue_final.latest-                                                                    consensus_wallstreet_revenue.wallstreet_revenue_final.latest)/
             consensus_wallstreet_revenue.wallstreet_revenue_final.latest)*100 
        },

           screen= ((morningstar.valuation.market_cap.latest > 1000000000) & (USEquityPricing.close.latest > 5) & (ConsensusEstimizeEPS.previous_actual_value.latest > 0) & (consensus_estimize_eps.estimize_eps_final.latest > 0) &                                   (consensus_estimize_eps.estimize_eps_final.latest > ConsensusEstimizeEPS.previous_actual_value.latest) & ((((morningstar.operation_ratios.roe.latest / morningstar.valuation_ratios.pe_ratio.latest)*100)*4) > 1) & (USEquityPricing.close.latest > SimpleMovingAverage(inputs= [USEquityPricing.close],                      window_length=50)))
                    
           
            #screen= ((morningstar.valuation.market_cap.latest > 1000000000) & (USEquityPricing.close.latest > 5) &                                     (consensus_estimize_eps.estimize_eps_final.latest > ConsensusEstimizeEPS.previous_actual_value.latest) & (consensus_estimize_eps.estimize_eps_final.latest > 0.01)   & ((AverageDollarVolume(window_length=20)) > 10**7) &  (morningstar.earnings_ratios.diluted_eps_growth.latest > 0.1) &  (morningstar.operation_ratios.revenue_growth.latest > 0.01) &(USEquityPricing.close.latest > SimpleMovingAverage(inputs= [USEquityPricing.close],                      window_length=50)) & ((((morningstar.operation_ratios.roe.latest /                                         morningstar.valuation_ratios.pe_ratio.latest)*100)*4)>1.5))
        
        )
        
    
#& (recent_returns > 0)
 

def before_trading_start(context, data):  
    context.data = pipeline_output('my_pipeline').dropna()
    
    context.data_sort = context.data.sort(['eps_growth'], ascending=False).iloc[:100]  
    
    #context.data_sort = context.data.sort(['eps_growth'], ascending=False).iloc[:100]
                        #I can modify the above to rank securities based on any column in my 
                        #pipeline. I must first create the column with the criteria im 
                        #looking for and then apply the sort criteria. 
    #context.long_secs = context.data_sort

    
    context.final_longs_sort = context.data_sort.sort(['dollar_volume'], ascending=False).iloc[:10]
    #15 sec 2015 to 0629 returned 8%
    #20 sec 2015 to 0629 returned 10%
    
    context.long_final = context.final_longs_sort
    
    context.security_list = context.long_final.index
    
    context.hedge = symbol('TLT')
    
    
    log.info(context.long_final)
    
def compute_weights(context):
    
    long_weight = 1.0/ len(context.long_final)
    
    return long_weight
    
    
def rebalance(context, data):
    
    long_weight = compute_weights(context)
    
    stock = context.security_list
    bond = context.hedge
    period = 70
    target_lev = .99
    pw = 0.5

    price_hedge = data.history(context.hedge, 'price', period+1, '1d')[0:-1]
    ret_sum1 = price_hedge.pct_change().sum()
    
    prices = data.history(context.long_final.index, 'price', period+1, '1d')[0:-1]
    ret_sum2 = prices.pct_change().sum()
    
    
    r_diff = ret_sum2[stock].sum() - ret_sum1
    print(r_diff)
    #record(r_diff = r_diff)
    if r_diff>0.0:        
        adpt = (1+r_diff)**pw-1.0
    elif r_diff<0.0:    
        adpt =-((1+abs(r_diff))**pw-1.0)
    else:    
        adpt =0.0   
  
    wt_stock = long_weight*(0.50+adpt)
    wt_bond = long_weight*(0.50-adpt)

    
    for stock in context.security_list:
        if data.can_trade(stock):
            if stock in context.long_final.index:
                order_target_percent(stock, wt_stock) 
    
    for stock in context.portfolio.positions:
        if stock not in context.security_list and data.can_trade(stock):
            order_target_percent(stock, 0)
   
    order_target_percent(context.hedge, wt_bond) 
    
    record(wt_stock = wt_stock, wt_bond = wt_bond)

    record(Leverage = context.account.leverage) 
    
    
    
    
    
    
    
    
    #def compute_weights(context):
    
    #long_weight = 0.95/ len(context.long_final)
    
    #return long_weight


#def rebalance(context, data):
    
   # long_weight = compute_weights(context)
    
    #for stock in context.security_list:
     #   if data.can_trade(stock):
      #      if stock in context.long_final.index:
       #         order_target_percent(stock, long_weight)
     # Sell all previously held positions not in our new context.security_list.
    #for stock in context.portfolio.positions:
     #   if stock not in context.security_list and data.can_trade(stock):
      #      order_target_percent(stock, 0)

    #log.info("This months's longs: "+", ".join([long_.symbol for long_ in context.long_final.index]))

    
#def record_vars(context, data):
    """
    This function is called at the end of each day and plots certain variables.
    """

    # Check how many long and short positions we have.
 #   longs = shorts = 0
  #  for position in context.portfolio.positions.itervalues():
   #     if position.amount > 0:
    #        longs += 1
     #   if position.amount < 0:
      #      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)
    
#062816 need to implement filter to remove N/As
#063016 see sample algo of weight for 50 day to view trading thesis
#criteria. Particularly the thoery that the worst performing stocks #over the past 5days will be the best performing stocks over the #next 5 days.
#too tired to continue. having problems at line 50. I was copying the algo portion from Weights Factor for 50 day MAVG.
#063016 Resumed in the morning and was able to get first algo trading by itself. returns not great and must continue to add relevant parameters to develop strategy. Good base to continue to build on. Will now proceed to change earning growth metrics to something more relevant to our IFG strategies.
#successfully implemented ranking system by roe/pe ratio. Ranking system grabbing only top 40 securities by roe/pe
#made plenty of progres thie evening. got a ranking system going 
#implemented eps 
#07/05/16 algorithm is working pretty good. I have got everything working the way I wanted and I think that the only thing missing is to tweak it to reduce down side. 
There was a runtime error.

You should check your return sum computations. You want ret_sum2 in line 128 to contain a pandas.Series of sums of daily returns for each stock. But it's possible you're instead creating a Series of sums of returns across stocks for each day. Either way, it shouldn't matter, because you're only using the gross sum across stocks and days. Remove [stock] in line 131.

Also, understand clearly how much of each stock you want to order. If wt_stock is the total percentage of all the stocks in your target portfolio, you wouldn't want this much for each stock, would you? Unless you have only one stock, you'll exceed your target leverage. Reread my previous message.

ahhhh ok. Sorry I got crazy confused there for a sec. This makes sense. Let me give it a go. For the wt_stock issue, would something like this make sense? wt_stock = (target_lev*(0.50+adpt)) / (len(context.long_final))

Yes. Or call it wt_each_stock.

Or insert

    wt_each_stock = wt_stock / len(context.long_final)  

after line 141 and change wt_stock to wt_each_stock in line 148, but not line 156.

Hi André thanks for your help again! Things are working better but still not 100%. Im attaching the latest backtest I ran last night. I think the problem might be that when rebalancing, it is both selling and buying the hedge at the same time. There are times when the stock level goes to 1.14 and the bond level goes to -0.14. Check it out see what you think. Im sure that it is a minor tweak at this point. Again, thanks for all your help!

Clone Algorithm
33
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
from quantopian.algorithm import attach_pipeline, pipeline_output  
from quantopian.pipeline import Pipeline  
from quantopian.pipeline.data.builtin import USEquityPricing  
from quantopian.pipeline.data import morningstar
from quantopian.pipeline.factors import SimpleMovingAverage, AverageDollarVolume, CustomFactor, Returns
from quantopian.pipeline.data.psychsignal import stocktwits

from quantopian.pipeline.data.estimize import (
    consensus_estimize_eps,
    consensus_wallstreet_eps,
    consensus_estimize_revenue, 
    consensus_wallstreet_revenue,
    ConsensusEstimizeEPS,
    ConsensusWallstreetEPS,
    ConsensusEstimizeRevenue, 
    ConsensusWallstreetRevenue
)

class Surprise(CustomFactor):
    window_length = 20
    inputs = [ConsensusEstimizeEPS.previous_actual_value,
              ConsensusEstimizeEPS.previous_mean]

    def compute(self, today, assets, out, actual_eps, estimize_eps):
        out[:] = (actual_eps[-1] - estimize_eps[-1])/(estimize_eps[-1] + 0)
       
        
def initialize(context):  
    attach_pipeline(my_pipeline(context), 'my_pipeline')  
    
    schedule_function(rebalance, 
                      date_rules.month_end(days_offset=0),
                      time_rules.market_open(hours = 1, minutes = 30))
                      
    
    set_slippage(slippage.FixedSlippage(spread=0.00))
    set_commission(commission.PerTrade(cost=1.00))
                    
    #context.my_leverage = 0.99
    

def my_pipeline(context):
    
    recent_returns = Returns(window_length=20)
    
    return Pipeline(  
        columns={  
           
            'close': USEquityPricing.close.latest,
            'dollar_volume': AverageDollarVolume(window_length=20), 
            'rec_returns' : recent_returns,
            'pct_surp': Surprise (),
            'rev_growth': morningstar.operation_ratios.revenue_growth.latest,
            'eps_growth' : morningstar.earnings_ratios.diluted_eps_growth.latest,
            'total_bullish' : stocktwits.bull_scored_messages .latest,
            'eps_est': consensus_estimize_eps.estimize_eps_final.latest,
            'actual_eps': ConsensusEstimizeEPS.previous_actual_value.latest,
            'num_est': consensus_estimize_eps.count.latest,
            'roe'  : morningstar.operation_ratios.roe.latest,
            'pe' : morningstar.valuation_ratios.pe_ratio.latest,
            'mkt_cap' : morningstar.valuation.market_cap.latest,
            '50d' : SimpleMovingAverage(inputs=[USEquityPricing.close], window_length=50),
            'roe_pe' : ((morningstar.operation_ratios.roe.latest / morningstar.valuation_ratios.pe_ratio.latest)*100)*4,  
            'ws_eps' : consensus_wallstreet_eps.wallstreet_eps_final.latest,
            'ws_rev' : consensus_wallstreet_revenue.wallstreet_revenue_final.latest,
            'es_rev' : consensus_estimize_revenue.estimize_revenue_final.latest,
            'rev_rank' : ((consensus_estimize_revenue.estimize_revenue_final.latest-                                                                    consensus_wallstreet_revenue.wallstreet_revenue_final.latest)/
             consensus_wallstreet_revenue.wallstreet_revenue_final.latest)*100 
        },

           screen= ((morningstar.valuation.market_cap.latest > 1000000000) & (USEquityPricing.close.latest > 5) & (ConsensusEstimizeEPS.previous_actual_value.latest > 0) & (consensus_estimize_eps.estimize_eps_final.latest > 0) &                                   (consensus_estimize_eps.estimize_eps_final.latest > ConsensusEstimizeEPS.previous_actual_value.latest) & ((((morningstar.operation_ratios.roe.latest / morningstar.valuation_ratios.pe_ratio.latest)*100)*4) > 1) & (USEquityPricing.close.latest > SimpleMovingAverage(inputs= [USEquityPricing.close],                      window_length=50)))
                    
           
            #screen= ((morningstar.valuation.market_cap.latest > 1000000000) & (USEquityPricing.close.latest > 5) &                                     (consensus_estimize_eps.estimize_eps_final.latest > ConsensusEstimizeEPS.previous_actual_value.latest) & (consensus_estimize_eps.estimize_eps_final.latest > 0.01)   & ((AverageDollarVolume(window_length=20)) > 10**7) &  (morningstar.earnings_ratios.diluted_eps_growth.latest > 0.1) &  (morningstar.operation_ratios.revenue_growth.latest > 0.01) &(USEquityPricing.close.latest > SimpleMovingAverage(inputs= [USEquityPricing.close],                      window_length=50)) & ((((morningstar.operation_ratios.roe.latest /                                         morningstar.valuation_ratios.pe_ratio.latest)*100)*4)>1.5))
        
        )
        
    
#& (recent_returns > 0)
 

def before_trading_start(context, data):  
    context.data = pipeline_output('my_pipeline').dropna()
    
    context.data_sort = context.data.sort(['eps_growth'], ascending=False).iloc[:100]  
    
    #context.data_sort = context.data.sort(['eps_growth'], ascending=False).iloc[:100]
                        #I can modify the above to rank securities based on any column in my 
                        #pipeline. I must first create the column with the criteria im 
                        #looking for and then apply the sort criteria. 
    #context.long_secs = context.data_sort

    
    context.final_longs_sort = context.data_sort.sort(['dollar_volume'], ascending=False).iloc[:10]
    #15 sec 2015 to 0629 returned 8%
    #20 sec 2015 to 0629 returned 10%
    
    context.long_final = context.final_longs_sort
    
    context.security_list = context.long_final.index
    
    context.hedge = symbol('TLT')
    
    
    log.info(context.long_final)
    
def compute_weights(context):
    
    long_weight = 1.0/ len(context.long_final)
    
    return long_weight
    
    
def rebalance(context, data):
    
    long_weight = compute_weights(context)
    
    stock = context.security_list
    bond = context.hedge
    period = 70
    target_lev = 1
    pw = 0.5

    price_hedge = data.history(context.hedge, 'price', period+1, '1d')[0:-1]
    ret_sum1 = price_hedge.pct_change().sum()
    
    prices = data.history(context.long_final.index, 'price', period+1, '1d')[0:-1]
    ret_sum2 = prices.pct_change().sum()
    
    
    r_diff = ret_sum2[stock].sum() - ret_sum1
    print(r_diff)
    #record(r_diff = r_diff)
    if r_diff>0.0:        
        adpt = (1+r_diff)**pw-1.0
    elif r_diff<0.0:    
        adpt =-((1+abs(r_diff))**pw-1.0)
    else:    
        adpt =0.0   
  
    wt_stock = target_lev*(0.50+adpt)
    wt_each_stock = wt_stock / len(context.long_final) 
    wt_bond = target_lev*(0.50-adpt)

   
    for stock in context.security_list:
        if data.can_trade(stock):
            if stock in context.long_final.index:
                order_target_percent(stock, wt_each_stock) 
    
    for stock in context.portfolio.positions:
        if stock not in context.security_list and data.can_trade(stock):
            order_target_percent(stock, 0)
   
    order_target_percent(context.hedge, wt_bond) 
     
    log.info("This months's longs: "+", ".join([long_.symbol for long_ in context.long_final.index]))

    
    record(wt_stock = wt_stock, wt_bond = wt_bond)

    record(Leverage = context.account.leverage) 
    
    
    
def record_vars(context, data):
    """
    This function is called at the end of each day and plots certain variables.
    """

    # Check how many long and short positions we have.
    longs = shorts = 0
    for position in context.portfolio.positions.itervalues():
        if position.amount > 0:
            longs += 1
        if position.amount < 0:
            shorts += 1


    
    
    
    
    
    
    #def compute_weights(context):
    
    #long_weight = 0.95/ len(context.long_final)
    
    #return long_weight


#def rebalance(context, data):
    
   # long_weight = compute_weights(context)
    
    #for stock in context.security_list:
     #   if data.can_trade(stock):
      #      if stock in context.long_final.index:
       #         order_target_percent(stock, long_weight)
     # Sell all previously held positions not in our new context.security_list.
    #for stock in context.portfolio.positions:
     #   if stock not in context.security_list and data.can_trade(stock):
      #      order_target_percent(stock, 0)

    #log.info("This months's longs: "+", ".join([long_.symbol for long_ in context.long_final.index]))

    
#def record_vars(context, data):
    """
    This function is called at the end of each day and plots certain variables.
    """

    # Check how many long and short positions we have.
 #   longs = shorts = 0
  #  for position in context.portfolio.positions.itervalues():
   #     if position.amount > 0:
    #        longs += 1
     #   if position.amount < 0:
      #      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)
    
#062816 need to implement filter to remove N/As
#063016 see sample algo of weight for 50 day to view trading thesis
#criteria. Particularly the thoery that the worst performing stocks #over the past 5days will be the best performing stocks over the #next 5 days.
#too tired to continue. having problems at line 50. I was copying the algo portion from Weights Factor for 50 day MAVG.
#063016 Resumed in the morning and was able to get first algo trading by itself. returns not great and must continue to add relevant parameters to develop strategy. Good base to continue to build on. Will now proceed to change earning growth metrics to something more relevant to our IFG strategies.
#successfully implemented ranking system by roe/pe ratio. Ranking system grabbing only top 40 securities by roe/pe
#made plenty of progres thie evening. got a ranking system going 
#implemented eps 
#07/05/16 algorithm is working pretty good. I have got everything working the way I wanted and I think that the only thing missing is to tweak it to reduce down side. 
There was a runtime error.

HI André hope you're doing well. Do you think you can take a look at this to see what the issue could be? I know its something with either the ordering process or weighting but just can't figure it out. I have made several changes but still can't figure it out.

I'm not sure I had seen this post before but it is most refreshing to read Vladimirs first post above.

I made a comment somewhere about sound and fury signifying nothing. It is my bet that if you revisited the vastly complex Quantopian approach in 10, 20 and 50 years hence and compared it to a simple stock bond rebalancing approach you would highly probably have done better with the latter.