Back to Community
Most diversified portfolio + leveraged ETFs

The logic is to diversify as much as possible and increase the leverage for extra return. No fancy timing just pure optimization. Optimization seems stable because there's no return guessing. Code is Robinhood ready. Remarkably does better than holding SPXL. Pardon the length of code as I use it as a template for all my theories.

Clone Algorithm
98
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
# Import the libraries we will use here
import math
import numpy as np
import pandas
from scipy.optimize import minimize
from quantopian.algorithm import attach_pipeline, pipeline_output
from quantopian.pipeline import Pipeline
from quantopian.pipeline.data.builtin import USEquityPricing
from quantopian.pipeline import CustomFactor
from quantopian.pipeline.factors import SimpleMovingAverage,AverageDollarVolume,Latest
from quantopian.pipeline.data import morningstar

# enable_logging = True
enable_logging = False
def loginfo(msg,*arg,**kwarg):
    if enable_logging: log.info(msg,arg,kwarg)

def get_vwaps_and_volumes(context,data,orders):
    vwap_hist = data.history(orders, ['price', 'volume'], context._day_minutes, '1m')
    volumes = vwap_hist['volume'].sum()
    vwap = (vwap_hist['price'] * vwap_hist['volume']).sum() / volumes
    return vwap,volumes

class OrderHandler:
    queue = {}
    safety_factor = 0.95
    vwap_order = True
    # vwap_order = False
    iceberg_order = True
    # iceberg_order = False
    volume_limit = 0.01
    order_duration = 30
    
    def push(self,security,leverage):
        self.queue[security] = leverage
        
    def clearQueue(self):
        self.queue = {}
        
    def run(self,context,data):
        open_orders = get_open_orders()
        if open_orders:
            if (context._day_minutes % self.order_duration) == 0:
                for sec, o in open_orders.iteritems():
                    for oo in o:
                        cancel_order(oo)
            else:
                return
    
        if not self.queue: return
        
        orders = []
        for security in self.queue:
            orders.append(security)
        currents = data.current(orders,['price','low','high'])
        
        vwaps,volumes = get_vwaps_and_volumes(context,data,orders)
        ceiling = max(context.curr_risk*context.risk_leverage,context.portfolio.portfolio_value)
        remaining = max(ceiling-context.portfolio.portfolio_value*context.account.leverage,0)
        if context.max_drawdown*context.risk_leverage <= 1.0 and context.hedge_shortable == False:
            remaining = context.portfolio.cash
            if context.real_money: remaining = context.account.settled_cash
        
        for security in self.queue.keys():
            leverage = self.queue[security]
            
            if not data.can_trade(security): continue
            
            price = currents['price'][security]
            vwap = vwaps[security]
            if math.isnan(vwap):
                vwap = price
            
            if security == context.riskless:
                if len(self.queue) == 1:
                    free_cash = context.portfolio.positions[security].amount*price + context.account.settled_cash*self.safety_factor
                    target = int( free_cash/price )
                else:
                    target = int( (context.portfolio.portfolio_value * leverage * self.safety_factor) / price )
            else:
                target = int( (context.curr_risk * leverage * self.safety_factor ) / price )
                
            shares = context.portfolio.positions[security].amount
            delta_shares = target - shares
            if self.iceberg_order:
                sign = np.sign(delta_shares)
                available = math.ceil(volumes[security]/context._day_minutes*self.order_duration*self.volume_limit)
                delta_shares = sign*min(available,np.abs(delta_shares))
                delta_shares = int(delta_shares)
            
            delta_lev = delta_shares*price
            if shares < 0:
                delta_lev *= -1
                
            if delta_shares > 0 and not context.real_money:
                if context.simulate_no_margin and context.last_sale and (get_datetime() - context.last_sale).days < 3:
                    continue
            
            if (target - shares) == 0:
                self.queue.pop(security,None)
                
            elif (remaining >= delta_lev):
            
                if self.vwap_order:
                    limit = vwap
                    if math.isnan(limit): continue
                    order(security,delta_shares,style=LimitOrder(limit))
                else:
                    order(security,delta_shares)
                    
                remaining -= max(delta_lev,0)
        
orderHandler = OrderHandler()

class UlcerIndex(CustomFactor):
    inputs = [USEquityPricing.close]

    def compute(self, today, asset_ids, out, close):
        max = np.maximum.accumulate(close,axis=0)
        dd = (max-close)/max
        dd = dd**2.0
        ui = np.sqrt(np.mean(dd,axis=0))
        out[:] = ui
        
class Value(CustomFactor):
    # inputs = [morningstar.valuation_ratios.ev_to_ebitda]
    inputs = [morningstar.income_statement.ebitda,morningstar.valuation.enterprise_value]

    # def compute(self, today, asset_ids, out, ratio):
        # out[:] = 1.0/ratio[-1]
        
    def compute(self, today, asset_ids, out, ebitda,ev):
        ev = np.nan_to_num(ev)
        ev = np.maximum(ev,1)
        out[:] = ebitda/ev
        
class Quality(CustomFactor):
    inputs = [morningstar.operation_ratios.roic]
    def compute(self, today, asset_ids, out, roic):
        out[:] = roic[-1]
        
class Volume(CustomFactor):
    inputs = [USEquityPricing.volume]

    def compute(self, today, asset_ids, out, vol):
        out[:] = np.nan_to_num(np.mean(vol,axis=0))
        
# The initialize function is the place to set your tradable universe and define any parameters. 
def initialize(context):
    # set_slippage(slippage.VolumeShareSlippage(volume_limit=1, price_impact=0.0))
    set_commission(commission.PerShare(cost=0, min_trade_cost=0))
    set_symbol_lookup_date('2016-01-01')
    set_long_only()
    
    context.alternate = symbols( # Switch to these stocks when hedging systematic risk
        'TLT', # 20+ Treasury 
        'GLD', # Gold
    )
    context.fixed = symbols(
            'SPXL', # SP500 3x bull
            'TNA', # Russell 2000 3x bull
            'DZK', # Developed 3x bull
            # 'DPK', # # Developed 3x bear
            'EDC', # Emerging 3x bull
            # 'EDZ', # Emerging 3x bear
            'TMF', # 20+ yr treasury 3x bull
            # 'UGLD', # Gold 3x bull
            
            # 'EDV',
            # 'VTI',
            # 'VNQ',
            # 'VNQI',
            # 'VPL',
            # 'VGK',
            # 'VWO',
            # 'VDE',
            # 'BIV',
            
            # 'VTI', # USA
            # 'EFA', # Developed
            # 'IYR', # REIT
            # 'EZU', # Europe
            # 'EWJ', # Japan
            # 'EEM', # Emerging
            # 'XLE', # Energy
            # 'TLT', # 20+ Treasury 
            # 'IEF', # 7-10 Treasury
            # 'HYG', # High yield bonds
            # 'LQD', # Corporate bonds
            # 'EMB', # Emerging market bonds
            # 'GLD', # Gold
            # 'FXE', # Euro
            # 'FXY', # Yen
    )
    
    # OPTIONS ###################################
    context.global_picks = False
    # context.global_picks = True
    # context.fixed_timing = True
    context.fixed_timing = False
    context.longs = []
    context.shorts = []
    context.leverage = {}
    context.benchmark = symbol('SPY')
    context.riskless = symbol('AGG')
    # context.riskless = symbol('BSV')
    context.ignore = [ # Stocks to ignore when picking
        context.riskless,   
        context.benchmark,
    ]
    context.max_drawdown = 1.0 # Portion of portfolio to risk
    context.risk_leverage = 1.0 # Portion leverage = max_drawdown * risk_leverage
    context.curr_risk = context.portfolio.portfolio_value*context.max_drawdown
    context.max_risk = context.curr_risk
    context.port_ceil = context.portfolio.portfolio_value
    context.exit_period = 5
    context.pick_period = 5
    context.trade_period = 1
    context.recalculate_period = context.pick_period
    context.lookback = 21*12 # Number of previous days to sample
    context.short_lookback = 21*12
    # context.hold_cash = False # Use or don't use excess cash to invest in riskless
    context.hold_cash = True # Use or don't use excess cash to invest in riskless
    context.weight_mode = 1
    context.real_money = False
    context.combined_optimization = False
    context.simulate_no_margin = True
    context.import_current_positions = True
    context.allocation_expanding_window = False
    
    context.last_sale = None
    context.last_buy = None
    context.pipeline_output = None
    
    context.hedge = True
    # context.hedge = False
    context.hedge_shortable = False
    # context.hedge_shortable = True
    # context.hedge_systematic = True
    context.hedge_systematic = False
    # context.hedge_drawdown_protection = True
    context.hedge_drawdown_protection = False
    # context.hedge_with_fixed = True
    context.hedge_with_fixed = False
    context.hedge_short_long_ratio = 1.0
    context.hedge_target_volatility = 1e9 # Annualized standard deviation of return
    
    context._day_minutes = 0
    context._day_count = -1   
    context.force_recalculate = True
    context._risk_on = True
    
    context.borrowing_rate = 1.02
    context.accrued_interest = 0
    
    context.long_size = 10
    context.short_size = 0
    
    context.max_pct_liquidity = 0.01
    context.min_dollar_volume = context.curr_risk/context.long_size/context.max_pct_liquidity
    # context.min_dollar_volume = 1e7
    # END #######################################
        
    if context.global_picks == True:
        pipe = Pipeline()
        attach_pipeline(pipe, name='my_pipeline')
        no_etfs = morningstar.valuation.market_cap.latest > 0
        # income = (morningstar.earnings_ratios.diluted_eps_growth > 0)\
        # | (morningstar.valuation_ratios.dividend_yield > 0)
        tradable = morningstar.share_class_reference.security_type.latest.startswith('ST00000001')\
        & (morningstar.share_class_reference.exchange_id.latest.startswith('NYS')\
        | morningstar.share_class_reference.exchange_id.latest.startswith('NAS'))
        liquidity = (morningstar.operation_ratios.interest_coverage > 1.5)\
        & (morningstar.operation_ratios.current_ratio.latest > 1.0)
        # & (morningstar.valuation_ratios.payout_ratio.latest < 1.0)
        dollar_volume = AverageDollarVolume(window_length = context.short_lookback)
        min_dv = dollar_volume >= context.min_dollar_volume
        mask = no_etfs & min_dv & liquidity
        f0 = 1.0/UlcerIndex(window_length = context.lookback)
        f1 = Value(window_length = 1)
        f1 = f1.percentile_between(50.0,100.0,mask=f1.isfinite() & tradable)
        f2 = Quality(window_length = 1)
        f2 = f2.percentile_between(80.0,100.0,mask=tradable)
        # f3 = -Latest([morningstar.operation_ratios.quick_ratio])
        # f3 = f3.percentile_between(90.0,100.0,mask=mask)
        
        pipe.add(f0,'f0')
        # pipe.add(f1,'f1')
        # pipe.add(f2,'f2')
        # pipe.add(f3,'f3')
        pipe.set_screen(mask & f1 & f2)
        # pipe.set_screen(mask)
        
    schedule_function(day_start,
        date_rules.every_day(),
        time_rules.market_open(hours = 0, minutes = 1))
        
    schedule_function(day_end,
        date_rules.every_day(),
        time_rules.market_close(hours = 0, minutes = 5))
        
def simulate_borrowing(context,data):
    shorts = 0
    longs = 0
    cash = context.portfolio.cash
    for sec,v in context.portfolio.positions.iteritems():
        delisted = 0
        if sec.end_date < get_datetime():
            delisted += np.abs(v.amount*v.last_sale_price)
            
        shares = v.amount
        if shares < 0:
            shorts += np.abs(shares)*v.last_sale_price - delisted
        else:
            longs += shares*v.last_sale_price - delisted
            
    daily_interest = (context.borrowing_rate-1.0)/252.0
    borrowed = shorts + max(0-(cash-1.5*shorts),0) # 1.5 = 150% short requirement
    context.accrued_interest += (borrowed + context.accrued_interest) * daily_interest
    
def before_trading_start(context,data):
    context._day_minutes = 0
    context._day_count += 1
    simulate_borrowing(context,data)

    context.pipeline_output = None
    if context.global_picks and context._day_count % context.pick_period == 0:
        context.pipeline_output = pipeline_output('my_pipeline').dropna(axis=0)
        
def exit_callback(context,data):
    # holding_period = 370
    # dt = get_datetime()
    # if context.last_buy:
        # count = (dt-context.last_buy).days
        # loginfo('{} days until rebalance'.format(holding_period-count))
        # if count < holding_period:
            # return context.alternate,context.alternate
    # context._day_count = 0
    longs,shorts = context.longs,context.shorts
    return longs,shorts
    
def is_market_down(context,data):
    prices = data.history([context.benchmark,context.riskless], 'price', context.lookback, '1d')
    a = prices.iloc[-1]/prices.iloc[0] - 1.0
    if not context.hold_cash:
        a = a - max(a[context.riskless],0)
    a = a[context.benchmark]
    b = prices.iloc[-1]/prices.mean()
    b = b[context.benchmark]
    market_down = a <= 0 and b <= 1
    return market_down
        
def exit_positions(context,data):
    if (context._day_count % context.exit_period) != 0: return
    
    market_down = False
    if context.hedge and context.hedge_systematic:
        market_down = is_market_down(context,data)
        
    if market_down:
        context._risk_on = False
        longs,shorts = context.longs,context.shorts
    else:
        context._risk_on = True
        longs,shorts = exit_callback(context,data)
        
    remove = np.union1d(longs,shorts)
    for sec in remove:
        context.leverage.pop(sec,None)
        orderHandler.push(sec,0)
    context.longs = np.setdiff1d(context.longs,remove)
    context.shorts = np.setdiff1d(context.shorts,remove)
            
def pipeline_filter(context,data):

    picks = context.pipeline_output
    picks = picks[~picks.index.isin(context.ignore)]
    picks = picks[~picks.index.isin(security_lists.leveraged_etf_list)]
    picks = picks.rank().sum(axis=1).order()
    
    longs = picks[-context.long_size:]
    shorts = picks[:context.short_size]
    
    longs = longs.index
    shorts = np.setdiff1d(shorts.index,context.longs)
    if len(longs) == 0 and len(shorts) == 0:
        loginfo('(!) Pipeline criteria found nothing')
    return longs,shorts
            
def repick(context,data): 
    if context._day_count % context.pick_period != 0: return
    # Find new stocks to go long/short
    # Exit any old stocks
    # Combine remaining stocks with new stocks
    
    fixed = context.fixed
    market_down = False
    longs,shorts = [],[]

    if context.hedge and context.hedge_systematic:
        market_down = is_market_down(context,data)
        if market_down:
            fixed = context.alternate
    
    if context.global_picks and not market_down:
        longs,shorts = pipeline_filter(context,data)    
    if context.import_current_positions:
        context.import_current_positions = False
        ilongs,ishorts = [],[]
        for sec,v in context.portfolio.positions.iteritems():
            if sec == context.riskless: continue
            if v.amount > 0:
                ilongs.append(sec)
            elif v.amount < 0:
                ishorts.append(sec)
            
            longs = np.setdiff1d(longs,ilongs)[:max(0,context.long_size-len(ilongs))]
            longs = np.union1d(longs,ilongs)
            shorts = np.setdiff1d(shorts,ishorts)[:max(0,context.short_size-len(ishorts))]
            shorts = np.setdiff1d(np.union1d(shorts, ishorts), longs)[-context.short_size:]
        
    if context.global_picks == False or context.hedge_with_fixed:
        prices = data.history(fixed, 'price', context.lookback, '1d').dropna(axis=1)
        prices = prices.loc[:,prices.columns.isin(fixed)]
        pratio = prices.iloc[-1]/prices.mean()
        
        r = prices.pct_change().dropna()
        rmean = r.mean()
        
        # yld = pandas.Series(context.fixed_yield.values(),index=context.fixed_yield.keys())
        # yld = np.log(yld)/252.0
        # rmean += yld
        
        if context.fixed_timing:
            long_condition = (rmean > 0) | (pratio > 1)
            flongs = rmean[long_condition]
            fshorts = rmean[~long_condition]
            flongs.sort()
            fshorts.sort()
            
            flongs = flongs[-context.long_size:].index
            fshorts = fshorts[:context.short_size].index
            fshorts = np.setdiff1d(fshorts,flongs)
        else:
            flongs = fixed
            fshorts = []

        if context.hedge_with_fixed:
            longs = np.setdiff1d(longs,flongs)[:max(0,context.long_size-len(flongs))]
            longs = np.union1d(longs,flongs)
            shorts = np.setdiff1d(shorts,fshorts)[:max(0,context.short_size-len(fshorts))]
            shorts = np.setdiff1d(np.union1d(shorts, fshorts), longs)[-context.short_size:]
        else:
            longs,shorts = flongs,fshorts
       
    remain_longs,remain_shorts = context.longs,context.shorts
    new_longs = np.setdiff1d(longs,remain_longs)[:max(context.long_size-len(remain_longs),0)]
    longs = np.union1d(remain_longs,new_longs)
    new_shorts = np.setdiff1d(shorts,remain_shorts)[:max(context.short_size-len(remain_shorts),0)]
    shorts = np.union1d(remain_shorts,new_shorts)
    shorts = np.setdiff1d(shorts,longs)
    
    if len(np.setdiff1d(longs,remain_longs)) > 0 or len(np.setdiff1d(shorts,remain_shorts)) > 0:
        context.longs = longs
        context.shorts = shorts            
        context.force_recalculate = True
            
        securities = np.concatenate((context.longs,context.shorts))
        context.leverage = dict.fromkeys(securities,0)
        
weight_modes = {
    0:'naive',
    1:'max_div',
    2:'min_var',
    3:'max_sharpe',
}
        
def min_corr(x,*args):
    corr = args[0]
    return np.dot(np.dot(x.T,corr),x)
    
def min_var(x,*args):
    cov = args[0]
    return np.dot(np.dot(x.T,cov),x)
    
def max_sharpe(x,*args):
    cov = args[0]
    mean = args[1]
    return -( np.dot(x,mean)-np.dot(np.dot(x.T,cov),x)/2.0 )
    
def jacobian(x,*args):
    mat = args[0]
    return 2*np.dot(x.T,mat)
    
def jac_sharpe(x,*args):
    cov = args[0]
    mean = args[1]
    return -( mean - np.dot(cov,x) )
    
def get_k(context,data,shorts=False):
    if shorts:
        if context.combined_optimization:
            sign = 1
            securities = np.union1d(context.longs,context.shorts)
        else:
            sign = -1
            securities = context.shorts
    else:
        sign = 1
        securities = context.longs
        
    if context.allocation_expanding_window:
        window_length = context._day_count+5
    else:
        window_length = context.short_lookback
        
    prices = data.history(securities, 'price', window_length, '1d').dropna(axis=1)
    r = prices.pct_change().dropna()
    k = None
        
    r = r[r.columns[r.columns.isin(securities)]]
    securities = r.columns
    
    k = pandas.Series(0, index=securities)
    
    if k.size > 0: # Most diversified portfolio
        if weight_modes[context.weight_mode] == 'naive':
            k += 1.0/len(securities)
        else:
            lam = 0.94
            com = 1./(1.-lam) - 1.
            # mean = r.mean().values
            # cov = r.cov().values
            # corr = r.corr().values
            cov = pandas.ewmcov(r,com=com,min_periods=window_length-1).iloc[-1].values
                            
            min_bnd = (shorts and context.combined_optimization and -1.0) or 0
            max_bnd = 1.0
            
            bounds = tuple((min_bnd,max_bnd) for x in securities)
            constr = (
                {'type': 'eq', 'fun': lambda x:  1.0-np.sum(np.abs(x))},
            )
            x0 = k.values
            x0 = np.add(x0,1.0/k.size)
            
            if weight_modes[context.weight_mode] == 'max_div':
                corr = pandas.ewmcorr(r,com=com,min_periods=window_length-1).iloc[-1].values
                result = minimize(min_corr, x0, jac=jacobian, args=(corr), constraints=constr, bounds=bounds)
            elif weight_modes[context.weight_mode] == 'min_var':
                result = minimize(min_var, x0, jac=jacobian, args=(cov), constraints=constr, bounds=bounds)
            elif weight_modes[context.weight_mode] == 'max_sharpe':
                mean = pandas.ewma(r,com=com,min_periods=window_length-1).iloc[-1].values
                result = minimize(max_sharpe, x0, jac=jac_sharpe, args=(cov,mean), constraints=constr, bounds=bounds)

            if result.success:
                x0 = result.x
                
            k = pandas.Series(x0,index=k.index)
            if weight_modes[context.weight_mode] == 'max_div':
                # volatility = r.std()
                volatility = pandas.ewmstd(r,com=com,min_periods=window_length-1).iloc[-1]
                k = k/volatility
            
    k = k / k.abs().sum() * context.risk_leverage
    k = k.fillna(0)
        
    return k*sign
            
def recalculate(context,data):
    if (not context.force_recalculate) and context._day_count % context.recalculate_period != 0: return
    
    k = get_k(context,data)
    securities = k.index
    prices = data.history(np.union1d(context.leverage.keys(),[context.benchmark,context.riskless]), 'price', context.lookback, '1d').bfill()
        
    if context.hedge: 
        longs = k
        shorts = pandas.Series(0,index=context.shorts)
        
        if context.hedge_shortable:
            if context.combined_optimization:
                longs = get_k(context,data,shorts=True)
                shorts = pandas.Series()
            else:
                shorts = get_k(context,data,shorts=True)
                shorts *= context.hedge_short_long_ratio
                
        if context.hedge_drawdown_protection and not context.combined_optimization:
            risk_r = prices.iloc[-1]/prices.iloc[0] - 1.0
            if not context.hold_cash:
                risk_r = risk_r - max(risk_r[context.riskless],0)
            pratio = prices.iloc[-1]/prices.mean()
            
            signal = (risk_r <= 0) & (pratio <=1)
            signal = risk_r[signal].index
            longs[longs.index.isin(signal)] -= longs[longs.index.isin(signal)]
            shorts[~shorts.index.isin(signal)] -= shorts[~shorts.index.isin(signal)]
            
        k = pandas.concat((longs,shorts))
        k = k / k.abs().sum() * context.risk_leverage
        k = k.fillna(value=0)
        securities = k.index
        
        lam = 0.94
        com = 1./(1.-lam) - 1.
        r = prices.pct_change().dropna()
        r = r[r.columns[r.columns.isin(k.index)]]
        cov = r.iloc[-context.short_lookback:].cov()
        # cov = pandas.ewmcov(r,com=com,min_periods=context.short_lookback-1).iloc[-1]
        k_var = np.dot(k.values, np.dot(cov.values,k.values))*252
        k_vol = k_var**0.5
        # record(volatility = k_vol)
        
        k_factor = min(context.hedge_target_volatility/k_vol,1.0)
        if not math.isnan(k_factor): k *= k_factor
            
    # Trading volume control
    v = data.history(securities, 'volume', context.short_lookback, '1d').fillna(0)
    dvol = (v * prices).mean()
    dvol = dvol[securities]
    
    dollars = context.curr_risk*k
    d_pct = (dollars / (dvol*max(context.recalculate_period/context.trade_period,1))).abs()
    epsilon = (context.max_pct_liquidity/d_pct).min()
    epsilon = min(1.0, epsilon)
    k = k * epsilon
        
    # QUEUE ORDERS #########################
    orderHandler.clearQueue()
    my_secs = np.concatenate((securities,context.ignore),axis=0)
    
    for sec in context.portfolio.positions:
        if (sec not in my_secs):
            orderHandler.push(sec,0)
    
    for i,sec in enumerate(securities):
        context.leverage[sec] = k[sec]
        orderHandler.push(sec,k[sec])
        
    context.force_recalculate = False
    
    loginfo('---')
    loginfo('Target allocation:')
    loginfo(k)
    loginfo('Orders queued: {}'.format(len(orderHandler.queue)))
    
def order_riskless(context,data):
    if not context.hold_cash: 
        k = np.sum(np.abs(context.leverage.values()))
        riskless_pct = max(1.0-context.max_drawdown*k,0)
        orderHandler.push(context.riskless,riskless_pct)
        # record(riskless=riskless_pct)
        
# The handle_data function is run every bar.    
def handle_data(context,data):
    # UPDATE RISK SIZE ##########################

    new_port = context.portfolio.portfolio_value*context.max_drawdown
    diff = context.portfolio.portfolio_value - context.port_ceil
    if diff > 0:
        context.curr_risk = new_port
        context.max_risk = new_port
        context.port_ceil = context.portfolio.portfolio_value
    else:
        context.curr_risk = context.max_risk + diff
        context.curr_risk = max(0,context.curr_risk)

    context._day_minutes += 1
    
    if (context._day_count % context.trade_period == 0):
        orderHandler.run(context,data)
        
    check_last_sale(context)
        
def day_start(context,data):
    exit_positions(context,data)
    repick(context,data)
    recalculate(context,data)
    order_riskless(context,data)
        
def day_end(context,data):
    long = 0
    short = 0
    total = 0
    
    for security,v in context.portfolio.positions.iteritems():
        asset = v.amount * v.last_sale_price
        if asset > 0:
            long += asset
        else:
            short += np.abs(asset)
            
    long = long/context.portfolio.portfolio_value
    short = short/context.portfolio.portfolio_value
    total += long + short
    
    record(long = long)
    # record(short = short)
    record(queue = len(orderHandler.queue))
    record(port_value = context.portfolio.portfolio_value)
    record(settled = context.account.settled_cash)
    # risk_record(context,data)
    # logging(context,data)
    
def logging(context,data):
    loginfo('---')
    loginfo('Risk size: {}'.format(context.curr_risk))
    loginfo('Port ceiling: {}'.format(context.port_ceil))
    loginfo('Portfolio value: {}'.format(context.portfolio.portfolio_value))
    loginfo('Cash: {}'.format(context.portfolio.cash))
    loginfo('Settled: {}'.format(context.account.settled_cash))
    loginfo('Accrued interest: {}'.format(context.accrued_interest))
    
    pos_sum = 0
    delisted_sum = 0
    positions = 0
    delisted = 0
    
    for sec,v in context.portfolio.positions.iteritems():
        if sec in context.leverage.keys():
            pos_sum += np.abs(v.amount*v.last_sale_price)
            positions += 1
        elif sec.end_date < get_datetime():
            delisted_sum += np.abs(v.amount*v.last_sale_price)
            delisted += 1
            
    loginfo('Real lev: {}'.format(pos_sum/context.portfolio.portfolio_value))
    loginfo('Delisted lev: {}'.format(delisted_sum/context.portfolio.portfolio_value))
    loginfo('Positions: {}'.format(positions))
    loginfo('Delisted: {}'.format(delisted))
    
def risk_record(context,data):
    if not '_init_rpr' in context:
        context._init_rpr = True
        context._max_shorts = 0
        context._min_cash = context.portfolio.cash
        context._peak_leverage = 0
        
    shorts = 0
    cash = context.portfolio.cash
    for sec,v in context.portfolio.positions.iteritems():
        delisted = 0
        if sec.end_date < get_datetime():
            delisted += np.abs(v.amount*v.last_sale_price)
            
        shares = v.amount
        if shares < 0:
            shorts += np.abs(shares*v.last_sale_price) - delisted
    
    context._max_shorts = max(context._max_shorts,shorts)
    context._min_cash = min(context._min_cash,cash)
    context._peak_leverage = max(context._peak_leverage,context.account.leverage)
    
    # record(min_cash = context._min_cash)
    # record(max_shorts = context._max_shorts)
    # record(peak_leverage = context._peak_leverage)
    record(risk_on = context._risk_on)

def check_last_sale(context):
    """
    To be used at the end of each bar. This checks if there were
    any sales made and sets that to `context.last_sale`.
    `context.last_sale` is then used in `cash_settlement_date` to
    simulate a T+3 Cash Settlement date
    
    To only be used for backtesting!
    """
    open_orders = get_open_orders()
    # If there are open orders check for the most recent sale
    if open_orders:
        most_recent_sale = []
        most_recent_buy = []
        for sec, order in open_orders.iteritems():
            for oo in order:
                if oo.amount < 0:
                    most_recent_sale.append(oo.created)
                if oo.amount > 0:
                    if oo.sid == context.riskless: continue
                    most_recent_buy.append(oo.created)
        if len(most_recent_sale) > 0:
            context.last_sale = max(most_recent_sale)
        if len(most_recent_buy) > 0:
            context.last_buy = max(most_recent_buy)
There was a runtime error.
1 response

As backtested above it has good consistant performance but uses all EFTs. Which is OK but, limits the back test date to 2010
If found a parameter "global_picks" and set it to true. Now it uses all stocks. The performance is about the same as SPY. Is this
what is expected? Interesting code, the first time I have seen someone here using Jascobians. I spent many years using them
writing differential equation solvers.

Clone Algorithm
8
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
# Import the libraries we will use here
import math
import numpy as np
import pandas
from scipy.optimize import minimize
from quantopian.algorithm import attach_pipeline, pipeline_output
from quantopian.pipeline import Pipeline
from quantopian.pipeline.data.builtin import USEquityPricing
from quantopian.pipeline import CustomFactor
from quantopian.pipeline.factors import SimpleMovingAverage,AverageDollarVolume,Latest
from quantopian.pipeline.data import morningstar

# enable_logging = True
enable_logging = False
def loginfo(msg,*arg,**kwarg):
    if enable_logging: log.info(msg,arg,kwarg)

def get_vwaps_and_volumes(context,data,orders):
    vwap_hist = data.history(orders, ['price', 'volume'], context._day_minutes, '1m')
    volumes = vwap_hist['volume'].sum()
    vwap = (vwap_hist['price'] * vwap_hist['volume']).sum() / volumes
    return vwap,volumes

class OrderHandler:
    queue = {}
    safety_factor = 0.95
    vwap_order = True
    # vwap_order = False
    iceberg_order = True
    # iceberg_order = False
    volume_limit = 0.01
    order_duration = 30
    
    def push(self,security,leverage):
        self.queue[security] = leverage
        
    def clearQueue(self):
        self.queue = {}
        
    def run(self,context,data):
        open_orders = get_open_orders()
        if open_orders:
            if (context._day_minutes % self.order_duration) == 0:
                for sec, o in open_orders.iteritems():
                    for oo in o:
                        cancel_order(oo)
            else:
                return
    
        if not self.queue: return
        
        orders = []
        for security in self.queue:
            orders.append(security)
        currents = data.current(orders,['price','low','high'])
        
        vwaps,volumes = get_vwaps_and_volumes(context,data,orders)
        ceiling = max(context.curr_risk*context.risk_leverage,context.portfolio.portfolio_value)
        remaining = max(ceiling-context.portfolio.portfolio_value*context.account.leverage,0)
        if context.max_drawdown*context.risk_leverage <= 1.0 and context.hedge_shortable == False:
            remaining = context.portfolio.cash
            if context.real_money: remaining = context.account.settled_cash
        
        for security in self.queue.keys():
            leverage = self.queue[security]
            
            if not data.can_trade(security): continue
            
            price = currents['price'][security]
            vwap = vwaps[security]
            if math.isnan(vwap):
                vwap = price
            
            if security == context.riskless:
                if len(self.queue) == 1:
                    free_cash = context.portfolio.positions[security].amount*price + context.account.settled_cash*self.safety_factor
                    target = int( free_cash/price )
                else:
                    target = int( (context.portfolio.portfolio_value * leverage * self.safety_factor) / price )
            else:
                target = int( (context.curr_risk * leverage * self.safety_factor ) / price )
                
            shares = context.portfolio.positions[security].amount
            delta_shares = target - shares
            if self.iceberg_order:
                sign = np.sign(delta_shares)
                available = math.ceil(volumes[security]/context._day_minutes*self.order_duration*self.volume_limit)
                delta_shares = sign*min(available,np.abs(delta_shares))
                delta_shares = int(delta_shares)
            
            delta_lev = delta_shares*price
            if shares < 0:
                delta_lev *= -1
                
            if delta_shares > 0 and not context.real_money:
                if context.simulate_no_margin and context.last_sale and (get_datetime() - context.last_sale).days < 3:
                    continue
            
            if (target - shares) == 0:
                self.queue.pop(security,None)
                
            elif (remaining >= delta_lev):
            
                if self.vwap_order:
                    limit = vwap
                    if math.isnan(limit): continue
                    order(security,delta_shares,style=LimitOrder(limit))
                else:
                    order(security,delta_shares)
                    
                remaining -= max(delta_lev,0)
        
orderHandler = OrderHandler()

class UlcerIndex(CustomFactor):
    inputs = [USEquityPricing.close]

    def compute(self, today, asset_ids, out, close):
        max = np.maximum.accumulate(close,axis=0)
        dd = (max-close)/max
        dd = dd**2.0
        ui = np.sqrt(np.mean(dd,axis=0))
        out[:] = ui
        
class Value(CustomFactor):
    # inputs = [morningstar.valuation_ratios.ev_to_ebitda]
    inputs = [morningstar.income_statement.ebitda,morningstar.valuation.enterprise_value]

    # def compute(self, today, asset_ids, out, ratio):
        # out[:] = 1.0/ratio[-1]
        
    def compute(self, today, asset_ids, out, ebitda,ev):
        ev = np.nan_to_num(ev)
        ev = np.maximum(ev,1)
        out[:] = ebitda/ev
        
class Quality(CustomFactor):
    inputs = [morningstar.operation_ratios.roic]
    def compute(self, today, asset_ids, out, roic):
        out[:] = roic[-1]
        
class Volume(CustomFactor):
    inputs = [USEquityPricing.volume]

    def compute(self, today, asset_ids, out, vol):
        out[:] = np.nan_to_num(np.mean(vol,axis=0))
        
# The initialize function is the place to set your tradable universe and define any parameters. 
def initialize(context):
    # set_slippage(slippage.VolumeShareSlippage(volume_limit=1, price_impact=0.0))
    set_commission(commission.PerShare(cost=0, min_trade_cost=0))
    set_symbol_lookup_date('2016-01-01')
    set_long_only()
    
    context.alternate = symbols( # Switch to these stocks when hedging systematic risk
        'TLT', # 20+ Treasury 
        'GLD', # Gold
    )
    context.fixed = symbols(
            'SPXL', # SP500 3x bull Nov 2008
            'TNA', # Russell 2000 3x bull Nov 2008
            'DZK', # Developed 3x bull Dec 2008
            # 'DPK', # # Developed 3x bear
            'EDC', # Emerging 3x bull DEC 2008
            # 'EDZ', # Emerging 3x bear
            'TMF', # 20+ yr treasury 3x bull  MAY 2009
            # 'UGLD', # Gold 3x bull
            
            # 'EDV',
            # 'VTI',
            # 'VNQ',
            # 'VNQI',
            # 'VPL',
            # 'VGK',
            # 'VWO',
            # 'VDE',
            # 'BIV',
            
            # 'VTI', # USA
            # 'EFA', # Developed
            # 'IYR', # REIT
            # 'EZU', # Europe
            # 'EWJ', # Japan
            # 'EEM', # Emerging
            # 'XLE', # Energy
            # 'TLT', # 20+ Treasury 
            # 'IEF', # 7-10 Treasury
            # 'HYG', # High yield bonds
            # 'LQD', # Corporate bonds
            # 'EMB', # Emerging market bonds
            # 'GLD', # Gold
            # 'FXE', # Euro
            # 'FXY', # Yen
    )
    
    # OPTIONS ###################################
    #context.global_picks = False
    context.global_picks = True
    # context.fixed_timing = True
    context.fixed_timing = False
    context.longs = []
    context.shorts = []
    context.leverage = {}
    context.benchmark = symbol('SPY')
    context.riskless = symbol('AGG')
    # context.riskless = symbol('BSV')
    context.ignore = [ # Stocks to ignore when picking
        context.riskless,   
        context.benchmark,
    ]
    context.max_drawdown = 1.0 # Portion of portfolio to risk
    context.risk_leverage = 1.0 # Portion leverage = max_drawdown * risk_leverage
    context.curr_risk = context.portfolio.portfolio_value*context.max_drawdown
    context.max_risk = context.curr_risk
    context.port_ceil = context.portfolio.portfolio_value
    context.exit_period = 5
    context.pick_period = 5
    context.trade_period = 1
    context.recalculate_period = context.pick_period
    context.lookback = 21*12 # Number of previous days to sample
    context.short_lookback = 21*12
    # context.hold_cash = False # Use or don't use excess cash to invest in riskless
    context.hold_cash = True # Use or don't use excess cash to invest in riskless
    context.weight_mode = 1
    context.real_money = False
    context.combined_optimization = False
    context.simulate_no_margin = True
    context.import_current_positions = True
    context.allocation_expanding_window = False
    
    context.last_sale = None
    context.last_buy = None
    context.pipeline_output = None
    
    context.hedge = True
    # context.hedge = False
    context.hedge_shortable = False
    # context.hedge_shortable = True
    # context.hedge_systematic = True
    context.hedge_systematic = False
    # context.hedge_drawdown_protection = True
    context.hedge_drawdown_protection = False
    # context.hedge_with_fixed = True
    context.hedge_with_fixed = False
    context.hedge_short_long_ratio = 1.0
    context.hedge_target_volatility = 1e9 # Annualized standard deviation of return
    
    context._day_minutes = 0
    context._day_count = -1   
    context.force_recalculate = True
    context._risk_on = True
    
    context.borrowing_rate = 1.02
    context.accrued_interest = 0
    
    context.long_size = 10
    context.short_size = 0
    
    context.max_pct_liquidity = 0.01
    context.min_dollar_volume = context.curr_risk/context.long_size/context.max_pct_liquidity
    # context.min_dollar_volume = 1e7
    # END #######################################
        
    if context.global_picks == True:
        pipe = Pipeline()
        attach_pipeline(pipe, name='my_pipeline')
        no_etfs = morningstar.valuation.market_cap.latest > 0
        # income = (morningstar.earnings_ratios.diluted_eps_growth > 0)\
        # | (morningstar.valuation_ratios.dividend_yield > 0)
        tradable = morningstar.share_class_reference.security_type.latest.startswith('ST00000001')\
        & (morningstar.share_class_reference.exchange_id.latest.startswith('NYS')\
        | morningstar.share_class_reference.exchange_id.latest.startswith('NAS'))
        liquidity = (morningstar.operation_ratios.interest_coverage > 1.5)\
        & (morningstar.operation_ratios.current_ratio.latest > 1.0)
        # & (morningstar.valuation_ratios.payout_ratio.latest < 1.0)
        dollar_volume = AverageDollarVolume(window_length = context.short_lookback)
        min_dv = dollar_volume >= context.min_dollar_volume
        mask = no_etfs & min_dv & liquidity
        f0 = 1.0/UlcerIndex(window_length = context.lookback)
        f1 = Value(window_length = 1)
        f1 = f1.percentile_between(50.0,100.0,mask=f1.isfinite() & tradable)
        f2 = Quality(window_length = 1)
        f2 = f2.percentile_between(80.0,100.0,mask=tradable)
        # f3 = -Latest([morningstar.operation_ratios.quick_ratio])
        # f3 = f3.percentile_between(90.0,100.0,mask=mask)
        
        pipe.add(f0,'f0')
        # pipe.add(f1,'f1')
        # pipe.add(f2,'f2')
        # pipe.add(f3,'f3')
        pipe.set_screen(mask & f1 & f2)
        # pipe.set_screen(mask)
        
    schedule_function(day_start,
        date_rules.every_day(),
        time_rules.market_open(hours = 0, minutes = 1))
        
    schedule_function(day_end,
        date_rules.every_day(),
        time_rules.market_close(hours = 0, minutes = 5))
        
def simulate_borrowing(context,data):
    shorts = 0
    longs = 0
    cash = context.portfolio.cash
    for sec,v in context.portfolio.positions.iteritems():
        delisted = 0
        if sec.end_date < get_datetime():
            delisted += np.abs(v.amount*v.last_sale_price)
            
        shares = v.amount
        if shares < 0:
            shorts += np.abs(shares)*v.last_sale_price - delisted
        else:
            longs += shares*v.last_sale_price - delisted
            
    daily_interest = (context.borrowing_rate-1.0)/252.0
    borrowed = shorts + max(0-(cash-1.5*shorts),0) # 1.5 = 150% short requirement
    context.accrued_interest += (borrowed + context.accrued_interest) * daily_interest
    
def before_trading_start(context,data):
    context._day_minutes = 0
    context._day_count += 1
    simulate_borrowing(context,data)

    context.pipeline_output = None
    if context.global_picks and context._day_count % context.pick_period == 0:
        context.pipeline_output = pipeline_output('my_pipeline').dropna(axis=0)
        
def exit_callback(context,data):
    # holding_period = 370
    # dt = get_datetime()
    # if context.last_buy:
        # count = (dt-context.last_buy).days
        # loginfo('{} days until rebalance'.format(holding_period-count))
        # if count < holding_period:
            # return context.alternate,context.alternate
    # context._day_count = 0
    longs,shorts = context.longs,context.shorts
    return longs,shorts
    
def is_market_down(context,data):
    prices = data.history([context.benchmark,context.riskless], 'price', context.lookback, '1d')
    a = prices.iloc[-1]/prices.iloc[0] - 1.0
    if not context.hold_cash:
        a = a - max(a[context.riskless],0)
    a = a[context.benchmark]
    b = prices.iloc[-1]/prices.mean()
    b = b[context.benchmark]
    market_down = a <= 0 and b <= 1
    return market_down
        
def exit_positions(context,data):
    if (context._day_count % context.exit_period) != 0: return
    
    market_down = False
    if context.hedge and context.hedge_systematic:
        market_down = is_market_down(context,data)
        
    if market_down:
        context._risk_on = False
        longs,shorts = context.longs,context.shorts
    else:
        context._risk_on = True
        longs,shorts = exit_callback(context,data)
        
    remove = np.union1d(longs,shorts)
    for sec in remove:
        context.leverage.pop(sec,None)
        orderHandler.push(sec,0)
    context.longs = np.setdiff1d(context.longs,remove)
    context.shorts = np.setdiff1d(context.shorts,remove)
            
def pipeline_filter(context,data):

    picks = context.pipeline_output
    picks = picks[~picks.index.isin(context.ignore)]
    picks = picks[~picks.index.isin(security_lists.leveraged_etf_list)]
    picks = picks.rank().sum(axis=1).order()
    
    longs = picks[-context.long_size:]
    shorts = picks[:context.short_size]
    
    longs = longs.index
    shorts = np.setdiff1d(shorts.index,context.longs)
    if len(longs) == 0 and len(shorts) == 0:
        loginfo('(!) Pipeline criteria found nothing')
    return longs,shorts
            
def repick(context,data): 
    if context._day_count % context.pick_period != 0: return
    # Find new stocks to go long/short
    # Exit any old stocks
    # Combine remaining stocks with new stocks
    
    fixed = context.fixed
    market_down = False
    longs,shorts = [],[]

    if context.hedge and context.hedge_systematic:
        market_down = is_market_down(context,data)
        if market_down:
            fixed = context.alternate
    
    if context.global_picks and not market_down:
        longs,shorts = pipeline_filter(context,data)    
    if context.import_current_positions:
        context.import_current_positions = False
        ilongs,ishorts = [],[]
        for sec,v in context.portfolio.positions.iteritems():
            if sec == context.riskless: continue
            if v.amount > 0:
                ilongs.append(sec)
            elif v.amount < 0:
                ishorts.append(sec)
            
            longs = np.setdiff1d(longs,ilongs)[:max(0,context.long_size-len(ilongs))]
            longs = np.union1d(longs,ilongs)
            shorts = np.setdiff1d(shorts,ishorts)[:max(0,context.short_size-len(ishorts))]
            shorts = np.setdiff1d(np.union1d(shorts, ishorts), longs)[-context.short_size:]
        
    if context.global_picks == False or context.hedge_with_fixed:
        prices = data.history(fixed, 'price', context.lookback, '1d').dropna(axis=1)
        prices = prices.loc[:,prices.columns.isin(fixed)]
        pratio = prices.iloc[-1]/prices.mean()
        
        r = prices.pct_change().dropna()
        rmean = r.mean()
        
        # yld = pandas.Series(context.fixed_yield.values(),index=context.fixed_yield.keys())
        # yld = np.log(yld)/252.0
        # rmean += yld
        
        if context.fixed_timing:
            long_condition = (rmean > 0) | (pratio > 1)
            flongs = rmean[long_condition]
            fshorts = rmean[~long_condition]
            flongs.sort()
            fshorts.sort()
            
            flongs = flongs[-context.long_size:].index
            fshorts = fshorts[:context.short_size].index
            fshorts = np.setdiff1d(fshorts,flongs)
        else:
            flongs = fixed
            fshorts = []

        if context.hedge_with_fixed:
            longs = np.setdiff1d(longs,flongs)[:max(0,context.long_size-len(flongs))]
            longs = np.union1d(longs,flongs)
            shorts = np.setdiff1d(shorts,fshorts)[:max(0,context.short_size-len(fshorts))]
            shorts = np.setdiff1d(np.union1d(shorts, fshorts), longs)[-context.short_size:]
        else:
            longs,shorts = flongs,fshorts
       
    remain_longs,remain_shorts = context.longs,context.shorts
    new_longs = np.setdiff1d(longs,remain_longs)[:max(context.long_size-len(remain_longs),0)]
    longs = np.union1d(remain_longs,new_longs)
    new_shorts = np.setdiff1d(shorts,remain_shorts)[:max(context.short_size-len(remain_shorts),0)]
    shorts = np.union1d(remain_shorts,new_shorts)
    shorts = np.setdiff1d(shorts,longs)
    
    if len(np.setdiff1d(longs,remain_longs)) > 0 or len(np.setdiff1d(shorts,remain_shorts)) > 0:
        context.longs = longs
        context.shorts = shorts            
        context.force_recalculate = True
            
        securities = np.concatenate((context.longs,context.shorts))
        context.leverage = dict.fromkeys(securities,0)
        
weight_modes = {
    0:'naive',
    1:'max_div',
    2:'min_var',
    3:'max_sharpe',
}
        
def min_corr(x,*args):
    corr = args[0]
    return np.dot(np.dot(x.T,corr),x)
    
def min_var(x,*args):
    cov = args[0]
    return np.dot(np.dot(x.T,cov),x)
    
def max_sharpe(x,*args):
    cov = args[0]
    mean = args[1]
    return -( np.dot(x,mean)-np.dot(np.dot(x.T,cov),x)/2.0 )
    
def jacobian(x,*args):
    mat = args[0]
    return 2*np.dot(x.T,mat)
    
def jac_sharpe(x,*args):
    cov = args[0]
    mean = args[1]
    return -( mean - np.dot(cov,x) )
    
def get_k(context,data,shorts=False):
    if shorts:
        if context.combined_optimization:
            sign = 1
            securities = np.union1d(context.longs,context.shorts)
        else:
            sign = -1
            securities = context.shorts
    else:
        sign = 1
        securities = context.longs
        
    if context.allocation_expanding_window:
        window_length = context._day_count+5
    else:
        window_length = context.short_lookback
        
    prices = data.history(securities, 'price', window_length, '1d').dropna(axis=1)
    r = prices.pct_change().dropna()
    k = None
        
    r = r[r.columns[r.columns.isin(securities)]]
    securities = r.columns
    
    k = pandas.Series(0, index=securities)
    
    if k.size > 0: # Most diversified portfolio
        if weight_modes[context.weight_mode] == 'naive':
            k += 1.0/len(securities)
        else:
            lam = 0.94
            com = 1./(1.-lam) - 1.
            # mean = r.mean().values
            # cov = r.cov().values
            # corr = r.corr().values
            cov = pandas.ewmcov(r,com=com,min_periods=window_length-1).iloc[-1].values
                            
            min_bnd = (shorts and context.combined_optimization and -1.0) or 0
            max_bnd = 1.0
            
            bounds = tuple((min_bnd,max_bnd) for x in securities)
            constr = (
                {'type': 'eq', 'fun': lambda x:  1.0-np.sum(np.abs(x))},
            )
            x0 = k.values
            x0 = np.add(x0,1.0/k.size)
            
            if weight_modes[context.weight_mode] == 'max_div':
                corr = pandas.ewmcorr(r,com=com,min_periods=window_length-1).iloc[-1].values
                result = minimize(min_corr, x0, jac=jacobian, args=(corr), constraints=constr, bounds=bounds)
            elif weight_modes[context.weight_mode] == 'min_var':
                result = minimize(min_var, x0, jac=jacobian, args=(cov), constraints=constr, bounds=bounds)
            elif weight_modes[context.weight_mode] == 'max_sharpe':
                mean = pandas.ewma(r,com=com,min_periods=window_length-1).iloc[-1].values
                result = minimize(max_sharpe, x0, jac=jac_sharpe, args=(cov,mean), constraints=constr, bounds=bounds)

            if result.success:
                x0 = result.x
                
            k = pandas.Series(x0,index=k.index)
            if weight_modes[context.weight_mode] == 'max_div':
                # volatility = r.std()
                volatility = pandas.ewmstd(r,com=com,min_periods=window_length-1).iloc[-1]
                k = k/volatility
            
    k = k / k.abs().sum() * context.risk_leverage
    k = k.fillna(0)
        
    return k*sign
            
def recalculate(context,data):
    if (not context.force_recalculate) and context._day_count % context.recalculate_period != 0: return
    
    k = get_k(context,data)
    securities = k.index
    prices = data.history(np.union1d(context.leverage.keys(),[context.benchmark,context.riskless]), 'price', context.lookback, '1d').bfill()
        
    if context.hedge: 
        longs = k
        shorts = pandas.Series(0,index=context.shorts)
        
        if context.hedge_shortable:
            if context.combined_optimization:
                longs = get_k(context,data,shorts=True)
                shorts = pandas.Series()
            else:
                shorts = get_k(context,data,shorts=True)
                shorts *= context.hedge_short_long_ratio
                
        if context.hedge_drawdown_protection and not context.combined_optimization:
            risk_r = prices.iloc[-1]/prices.iloc[0] - 1.0
            if not context.hold_cash:
                risk_r = risk_r - max(risk_r[context.riskless],0)
            pratio = prices.iloc[-1]/prices.mean()
            
            signal = (risk_r <= 0) & (pratio <=1)
            signal = risk_r[signal].index
            longs[longs.index.isin(signal)] -= longs[longs.index.isin(signal)]
            shorts[~shorts.index.isin(signal)] -= shorts[~shorts.index.isin(signal)]
            
        k = pandas.concat((longs,shorts))
        k = k / k.abs().sum() * context.risk_leverage
        k = k.fillna(value=0)
        securities = k.index
        
        lam = 0.94
        com = 1./(1.-lam) - 1.
        r = prices.pct_change().dropna()
        r = r[r.columns[r.columns.isin(k.index)]]
        cov = r.iloc[-context.short_lookback:].cov()
        # cov = pandas.ewmcov(r,com=com,min_periods=context.short_lookback-1).iloc[-1]
        k_var = np.dot(k.values, np.dot(cov.values,k.values))*252
        k_vol = k_var**0.5
        # record(volatility = k_vol)
        
        k_factor = min(context.hedge_target_volatility/k_vol,1.0)
        if not math.isnan(k_factor): k *= k_factor
            
    # Trading volume control
    v = data.history(securities, 'volume', context.short_lookback, '1d').fillna(0)
    dvol = (v * prices).mean()
    dvol = dvol[securities]
    
    dollars = context.curr_risk*k
    d_pct = (dollars / (dvol*max(context.recalculate_period/context.trade_period,1))).abs()
    epsilon = (context.max_pct_liquidity/d_pct).min()
    epsilon = min(1.0, epsilon)
    k = k * epsilon
        
    # QUEUE ORDERS #########################
    orderHandler.clearQueue()
    my_secs = np.concatenate((securities,context.ignore),axis=0)
    
    for sec in context.portfolio.positions:
        if (sec not in my_secs):
            orderHandler.push(sec,0)
    
    for i,sec in enumerate(securities):
        context.leverage[sec] = k[sec]
        orderHandler.push(sec,k[sec])
        
    context.force_recalculate = False
    
    loginfo('---')
    loginfo('Target allocation:')
    loginfo(k)
    loginfo('Orders queued: {}'.format(len(orderHandler.queue)))
    
def order_riskless(context,data):
    if not context.hold_cash: 
        k = np.sum(np.abs(context.leverage.values()))
        riskless_pct = max(1.0-context.max_drawdown*k,0)
        orderHandler.push(context.riskless,riskless_pct)
        # record(riskless=riskless_pct)
        
# The handle_data function is run every bar.    
def handle_data(context,data):
    # UPDATE RISK SIZE ##########################

    new_port = context.portfolio.portfolio_value*context.max_drawdown
    diff = context.portfolio.portfolio_value - context.port_ceil
    if diff > 0:
        context.curr_risk = new_port
        context.max_risk = new_port
        context.port_ceil = context.portfolio.portfolio_value
    else:
        context.curr_risk = context.max_risk + diff
        context.curr_risk = max(0,context.curr_risk)

    context._day_minutes += 1
    
    if (context._day_count % context.trade_period == 0):
        orderHandler.run(context,data)
        
    check_last_sale(context)
        
def day_start(context,data):
    exit_positions(context,data)
    repick(context,data)
    recalculate(context,data)
    order_riskless(context,data)
        
def day_end(context,data):
    long = 0
    short = 0
    total = 0
    
    for security,v in context.portfolio.positions.iteritems():
        asset = v.amount * v.last_sale_price
        if asset > 0:
            long += asset
        else:
            short += np.abs(asset)
            
    long = long/context.portfolio.portfolio_value
    short = short/context.portfolio.portfolio_value
    total += long + short
    
    record(long = long)
    # record(short = short)
    record(queue = len(orderHandler.queue))
    record(port_value = context.portfolio.portfolio_value)
    record(settled = context.account.settled_cash)
    # risk_record(context,data)
    # logging(context,data)
    
def logging(context,data):
    loginfo('---')
    loginfo('Risk size: {}'.format(context.curr_risk))
    loginfo('Port ceiling: {}'.format(context.port_ceil))
    loginfo('Portfolio value: {}'.format(context.portfolio.portfolio_value))
    loginfo('Cash: {}'.format(context.portfolio.cash))
    loginfo('Settled: {}'.format(context.account.settled_cash))
    loginfo('Accrued interest: {}'.format(context.accrued_interest))
    
    pos_sum = 0
    delisted_sum = 0
    positions = 0
    delisted = 0
    
    for sec,v in context.portfolio.positions.iteritems():
        if sec in context.leverage.keys():
            pos_sum += np.abs(v.amount*v.last_sale_price)
            positions += 1
        elif sec.end_date < get_datetime():
            delisted_sum += np.abs(v.amount*v.last_sale_price)
            delisted += 1
            
    loginfo('Real lev: {}'.format(pos_sum/context.portfolio.portfolio_value))
    loginfo('Delisted lev: {}'.format(delisted_sum/context.portfolio.portfolio_value))
    loginfo('Positions: {}'.format(positions))
    loginfo('Delisted: {}'.format(delisted))
    
def risk_record(context,data):
    if not '_init_rpr' in context:
        context._init_rpr = True
        context._max_shorts = 0
        context._min_cash = context.portfolio.cash
        context._peak_leverage = 0
        
    shorts = 0
    cash = context.portfolio.cash
    for sec,v in context.portfolio.positions.iteritems():
        delisted = 0
        if sec.end_date < get_datetime():
            delisted += np.abs(v.amount*v.last_sale_price)
            
        shares = v.amount
        if shares < 0:
            shorts += np.abs(shares*v.last_sale_price) - delisted
    
    context._max_shorts = max(context._max_shorts,shorts)
    context._min_cash = min(context._min_cash,cash)
    context._peak_leverage = max(context._peak_leverage,context.account.leverage)
    
    # record(min_cash = context._min_cash)
    # record(max_shorts = context._max_shorts)
    # record(peak_leverage = context._peak_leverage)
    record(risk_on = context._risk_on)

def check_last_sale(context):
    """
    To be used at the end of each bar. This checks if there were
    any sales made and sets that to `context.last_sale`.
    `context.last_sale` is then used in `cash_settlement_date` to
    simulate a T+3 Cash Settlement date
    
    To only be used for backtesting!
    """
    open_orders = get_open_orders()
    # If there are open orders check for the most recent sale
    if open_orders:
        most_recent_sale = []
        most_recent_buy = []
        for sec, order in open_orders.iteritems():
            for oo in order:
                if oo.amount < 0:
                    most_recent_sale.append(oo.created)
                if oo.amount > 0:
                    if oo.sid == context.riskless: continue
                    most_recent_buy.append(oo.created)
        if len(most_recent_sale) > 0:
            context.last_sale = max(most_recent_sale)
        if len(most_recent_buy) > 0:
            context.last_buy = max(most_recent_buy)
There was a runtime error.