Back to Community
Volatility Bias - up range / total range strategy
Clone Algorithm
116
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
import math
import numpy as np
from collections import deque

weightPeriods = 33
triggerPeriods = 5

def initialize(context):
    secMgr = SecurityManager(weightPeriods)
    secMgr.Add("XLB", sid(19654), 1) # Materials Select Sector SPDR             
    secMgr.Add("XLE", sid(19655), 1) # Energy Select Sector SPDR                
    secMgr.Add("XLF", sid(19656), 1) # Financial Select Sector SPDR             
    secMgr.Add("XLI", sid(19657), 1) # Industrial Select Sector SPDR            
    secMgr.Add("XLK", sid(19658), 1) # Technology Select Sector SPDR            
    secMgr.Add("XLP", sid(19659), 1) # Consumer Staples Select Sector SPDR      
    secMgr.Add("XLU", sid(19660), 1) # Utilities Select Sector SPDR             
    secMgr.Add("XLV", sid(19661), 1) # Healthcare Select Sector SPDR            
    secMgr.Add("XLY", sid(19662), 1) # Consumer Discretionary Select Sector SPDR
    secMgr.Add("AGG", sid(25485), 1) # ISHARES CORE U.S. AGGREGATE BONDS 
    context.SecMgr = secMgr
    context.priorTotalWeight = 1.0
    context.period = 0
    
    set_commission(commission.PerTrade(cost=1.0))
    set_slippage(TradeAtTheOpenSlippageModel(.1))
    
def handle_data(context, data):
    context.SecMgr.Update(data)    
    context.period += 1
    if (context.period < weightPeriods):
        return
    
    for security in context.SecMgr.GetSecurities():
        if (security.Enabled):
            if (security.Trigger < .30):
                if (security.Weight > .45):
                    order_target_percent(security.Sid, security.Portion)
            elif (security.Trigger > .75 or security.Weight < .30):
                order_target_percent(security.Sid, 0)
            
    record(Weight=context.SecMgr.GetSecurities()[0].Weight,\
           Trigger=context.SecMgr.GetSecurities()[0].Trigger)
   
################################################################                
class SecurityManager(object):
    '''Class to wrap securities'''

    def __init__(self, periods):
        self.stockList = {}
        self.Periods = periods

    def __str__(self):
        toString = "\tSymbols:{0}\n".format(self.stockList.keys())
        return toString 
    
    def Count(self):
        return len(self.GetSecurities())
    
    def Add(self, symbol, sid, portion):
         self.stockList[symbol] = Security(symbol, sid, portion, self.Periods)

    def Update(self, data):
        totalWeight = 0.0
        for sec in self.stockList.values():
            if sec.Sid not in data:
                sec.Weight = 0.0
                sec.Enabled = False
                continue
            sec.UpdatePrices(data)
            sec.SetWeight()
            totalWeight += sec.Weight
            
        if (totalWeight > 0.0):            
            for sec in self.stockList.values():
                sec.Portion = sec.Weight / totalWeight;
        
        return totalWeight
        
    def GetSecurities(self):
        return self.stockList.values()

   
#################################################################
class Security(object):
    '''Class to wrap security'''

    def __init__(self, symbol, sid, portion, periods):
        self.Symbol = symbol
        self.Sid = sid
        self.Portion = portion        
        self.Open = deque(maxlen=periods)
        self.High = deque(maxlen=periods)
        self.Low = deque(maxlen=periods)
        self.Close = deque(maxlen=periods)
        self.Weight = 0.0
        self.Trigger = 0.0
        self.Enabled = True
            
    def __str__(self):
        toString = "\tSymbol:{0} weight:{1}\n".format(self.Symbol, self.Weight)
        return toString 
    
    def UpdatePrices(self, data):
        self.Open.append(data[self.Sid].open_price)
        self.High.append(data[self.Sid].high)
        self.Low.append(data[self.Sid].low)
        self.Close.append(data[self.Sid].close_price)
            
    def SetWeight(self):
        upPortion = 0
        dnPortion = 0
        span = len(self.Close)
        for i in range(0, span):
            if (self.Close[i] > self.Open[i]):
                upPortion += (i + 1) * (self.High[i] - self.Low[i])
            else:
                dnPortion += (i + 1) * (self.High[i] - self.Low[i])
        factor = upPortion / (upPortion + dnPortion)
        self.Weight = factor
        
        upPortion = 0
        dnPortion = 0
        if (span > triggerPeriods):
            newStart = span - triggerPeriods
            for i in range(0, 5):
                if (self.Close[newStart + i] > self.Open[newStart + i]):
                    upPortion += (i + 1) * (self.High[newStart + i] - self.Low[newStart + i])
                else:
                    dnPortion += (i + 1) * (self.High[newStart + i] - self.Low[newStart + i])
            factor = upPortion / (upPortion + dnPortion)
            self.Trigger = factor
        
        
        
########################################################    
class TradeAtTheOpenSlippageModel(slippage.SlippageModel):
    def __init__(self, fractionOfOpenCloseRange):
        self.fractionOfOpenCloseRange = fractionOfOpenCloseRange

    def process_order(self, trade_bar, order):
        openPrice = trade_bar.open_price
        closePrice = trade_bar.price
        ocRange = closePrice - openPrice
        ocRange = ocRange * self.fractionOfOpenCloseRange
        targetExecutionPrice = openPrice + ocRange
            
        # Create the transaction using the new price we've calculated.
        return slippage.create_transaction(
            trade_bar,
            order,
            targetExecutionPrice,
            order.amount
        )
        
''' Archive
    
    #context.SecMgr.Add("SPY", sid(8554), 1) # SPDR S&P 500 ETF TRUST    
    #context.SecMgr.Add("MDY", sid(12915), 1) # SPDR S&P MIDCAP 400 ETF TRUST
    #context.SecMgr.Add("RSP", sid(24744), 1) # GUGGENHEIM S&P 500 EQUAL WEIGH
    #context.SecMgr.Add("VTI", sid(22739), 1) # VANGUARD TOTAL STOCK MARKET ETF
    #context.SecMgr.Add("VBR", sid(25901), 1) # VANGUARD SMALL-CAP VALUE ETF
    #context.SecMgr.Add("AGG", sid(25485), 1) # ISHARES CORE U.S. AGGREGATE BO


                
            #print("W:{}".format( security.Weight))
            #print("T:{}".format( security.Trigger))

#    for security in context.SecMgr.GetSecurities():
#        if (security.Enabled):
#            if (security.Weight > .55):
#                if (security.Trigger < .25):
#                    order_target_percent(security.Sid, securiyt.Portion)
#            else:
#                order_target_percent(security.Sid, .25)
#            #print("W:{}".format( security.Weight))
#            #print("T:{}".format( security.Trigger))


'''
There was a runtime error.
27 responses

Nice! I remember a strategy to find high beta-bias stocks vs low beta-bias stocks, where one would sort the universe on beta_up / beta_down, long the top percentile and short the bottom. Probably suffers from the same problem as momentum at market bottoms, but I haven't backtested it in a while.

Hello Anony,

A couple quick thoughts:

--The algo doesn't perform very well beyond the "Great Recession" downturn, right? So, I'm wondering what is gained?
--Aside from the bond component, you are dealing with sectors of the S&P 500 (SPY). Would it make sense to measure the volatility relative to SPY? It seems that the overall market volatility should be factored out, to measure the sector-dependent volatility. Kind of a fuzzy thought at this point, but I have a simple algo in mind to see if it makes sense.

Grant

Just a hobby for me, at this point. As you must already figure, I have not found the holy grail. And I do not have the time/energy/experience for more than some sort of plain vanilla monthly/quarterly asset allocation algo. At this point, I'm waiting to see how much that's gonna cost through Quantopian/IB. It might make sense--we'll see. --Grant

Hello Anony,

In your VolBias code, why do you use the (i+1) multiplier:

        upPortion = 0  
        dnPortion = 0  
        span = len(self.Close)  
        for i in range(0, span):  
            if (self.Close[i] > self.Open[i]):  
                upPortion += (i + 1) * (self.High[i] - self.Low[i])  
            else:  
                dnPortion += (i + 1) * (self.High[i] - self.Low[i])  
        factor = upPortion / (upPortion + dnPortion)  
        self.Weight = factor  

Grant

Hi Anony, I am about to take a stab at your very interesting idea. Where did you come up with the initial thought? Also, how did you pick the portfolio? I see you mention something about "Q", what's that?

Hello Anony,

I started to play around with your approach, using my own coding style (see attached for a draft). Would you mind fleshing out a bit the indicator and trading rules? I'll see if I can replicate your result.

Sorry, I'm not yet up on Python object-oriented programming, so with a little guidance I should be able to decipher your code.

Grant

Clone Algorithm
25
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
import numpy as np
from pytz import timezone

trading_freq = 5 # trading frequency, days

def initialize(context):
    context.stocks = [ sid(19654),  # Materials Select Sector SPDR             
                       sid(19655),  # Energy Select Sector SPDR                
                       sid(19656),  # Financial Select Sector SPDR             
                       sid(19657),  # Industrial Select Sector SPDR            
                       sid(19658),  # Technology Select Sector SPDR            
                       sid(19659),  # Consumer Staples Select Sector SPDR      
                       sid(19660),  # Utilities Select Sector SPDR             
                       sid(19661),  # Healthcare Select Sector SPDR            
                       sid(19662),  # Consumer Discretionary Select Sector SPDR
                       sid(33652) ] # Vanguard Total Bond Market ETF
    
    context.day_count = -1
    
    context.allocation = -1.0*np.ones_like(context.stocks)

def handle_data(context, data):
    
    # Trade only once per day
    loc_dt = get_datetime().astimezone(timezone('US/Eastern'))
    if loc_dt.hour == 16 and loc_dt.minute == 0:
        context.day_count += 1
        pass
    else:
        return
    
    # Limit trading frequency
    if context.day_count % trading_freq != 0.0:
        return
    
    opn = history(60,'1d','open_price').as_matrix(context.stocks)
    close = history(60,'1d','close_price').as_matrix(context.stocks)
    low = history(60,'1d','low').as_matrix(context.stocks)
    high = history(60,'1d','high').as_matrix(context.stocks)
    
    if np.isnan(np.sum(opn)):
        return
    if np.isnan(np.sum(close)):
        return
    if np.isnan(np.sum(low)):
        return
    if np.isnan(np.sum(high)):
        return
  
    rng = high - low
    
    cls_opn = close - opn
    up_down = np.sign(cls_opn)
    up = np.copy(up_down)
    up[up < 0] = 0
    down = np.copy(up_down)
    down[down > 0] = 0
    
    rng_up = np.multiply(rng,up)
    rng_down = np.multiply(rng,-down)
    
    denom = np.sum(rng_up,axis=0) + np.sum(rng_down,axis=0)
    
    allocation = np.sum(rng_up,axis=0)/denom
    
    print allocation
    
    denom = np.sum(allocation)
    if denom != 0.0:
        allocation = allocation/np.sum(allocation)
        
    # return if allocation unchanged
    if np.array_equal(context.allocation,allocation):
        return
    
    context.allocation = allocation
    
    for stock,percent in zip(context.stocks,allocation):
        order_target_percent(stock,percent)
There was a runtime error.

Hi Anony, thanks for the explanations, I'll be porting your algo to my quantshim framework too, as this is the best way for me to learn. Your Security/SecurityMgr objects are actually already similar to mine, so think it should be easy-peasy.

Thanks Anony,

Another detail:

record(Weight=context.SecMgr.GetSecurities()[0].Weight,\  
           Trigger=context.SecMgr.GetSecurities()[0].Trigger)  

Are you just plotting the weight and trigger for one security, as a check that the algo is working properly (and perhaps to estimate your entry/maintenance/exit conditions)? Or is something else going on?

Also, I gather that your linear weighting versus time (the period(0...n) mutiplier) serves to bias the VolBias toward more recent changes, correct? In this industry, I see that this weighting is conventionally called a weighted moving average (WMA) (see http://www.tradestation.com/education/labs/analysis-concepts/a-comparative-study-of-moving-averages). Correct?

Grant

@Anony, do you mind explaining the reasoning/mechanisms behind your slippage model, I commented out the set_slippage line and it doesn't perform as well with the default slippage model.

Clone Algorithm
0
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
import math
import numpy as np
from collections import deque

weightPeriods = 42
triggerPeriods = 4

def initialize(context):
    secMgr = SecurityManager(weightPeriods)
    secMgr.Add("MDY", sid(12915), 1) # SPDR S&P MIDCAP 400 ETF TRUST             
    secMgr.Add("XLB", sid(19654), 1) # Materials Select Sector SPDR             
    secMgr.Add("XLE", sid(19655), 1) # Energy Select Sector SPDR                
    secMgr.Add("XLF", sid(19656), 1) # Financial Select Sector SPDR             
    secMgr.Add("XLI", sid(19657), 1) # Industrial Select Sector SPDR            
    secMgr.Add("XLK", sid(19658), 1) # Technology Select Sector SPDR            
    secMgr.Add("XLP", sid(19659), 1) # Consumer Staples Select Sector SPDR      
    secMgr.Add("XLU", sid(19660), 1) # Utilities Select Sector SPDR             
    secMgr.Add("XLV", sid(19661), 1) # Healthcare Select Sector SPDR            
    secMgr.Add("XLY", sid(19662), 1) # Consumer Discretionary Select Sector SPDR
    secMgr.Add("AGG", sid(25485), 1) # ISHARES CORE U.S. AGGREGATE BONDS 
    context.SecMgr = secMgr
    context.priorTotalWeight = 1.0
    context.period = 0
    
    set_commission(commission.PerTrade(cost=1.0))
    # set_slippage(TradeAtTheOpenSlippageModel(.1))
    
def handle_data(context, data):
    context.SecMgr.Update(data)    
    context.period += 1
    if (context.period < weightPeriods):
        return
    
    totalWeight = 0
    entries = {}
    exits = {}
    for security in context.SecMgr.GetSecurities():
        if (security.Enabled):
            if (security.Trigger < .15):
                if (security.Weight > .50):
                    entries[security] = security.Weight
                    totalWeight += security.Weight
                else:
                    exits[security] = 0
            elif (context.portfolio.positions[security.Sid].amount > 0):
                if (security.Trigger > .50 and security.Trigger < .80):
                    entries[security] = security.Weight
                    totalWeight += security.Weight
                else:
                    exits[security] = 0
            else:       
                exits[security] = 0

    if (totalWeight > 0.0):
        for security in entries.keys():
            security.Weight = entries[security] / totalWeight;
   
    for security in entries.keys():
        order_target_percent(security.Sid, security.Weight)
    for security in exits.keys():
        order_target_percent(security.Sid, 0)
            
    record(Weight=context.SecMgr.GetSecurities()[0].Weight,\
           Trigger=context.SecMgr.GetSecurities()[0].Trigger)
   
################################################################                
class SecurityManager(object):
    '''Class to wrap securities'''

    def __init__(self, periods):
        self.stockList = {}
        self.Periods = periods

    def __str__(self):
        toString = "\tSymbols:{0}\n".format(self.stockList.keys())
        return toString 
    
    def Count(self):
        return len(self.GetSecurities())
    
    def Add(self, symbol, sid, portion):
         self.stockList[symbol] = Security(symbol, sid, portion, self.Periods)

    def Update(self, data):
        totalWeight = 0.0
        for sec in self.stockList.values():
            if sec.Sid not in data:
                sec.Weight = 0.0
                sec.Enabled = False
                continue
            sec.UpdatePrices(data)
            sec.SetWeight()
            totalWeight += sec.Weight
            sec.Portion = sec.Weight
            
        #if (totalWeight > 0.0):            
        #    for sec in self.stockList.values():
        #        sec.Portion = sec.Weight / totalWeight;
        
        return totalWeight
        
    def GetSecurities(self):
        return self.stockList.values()

   
#################################################################
class Security(object):
    '''Class to wrap security'''

    def __init__(self, symbol, sid, portion, periods):
        self.Symbol = symbol
        self.Sid = sid
        self.Portion = portion        
        self.Open = deque(maxlen=periods)
        self.High = deque(maxlen=periods)
        self.Low = deque(maxlen=periods)
        self.Close = deque(maxlen=periods)
        self.Weight = 0.0
        self.Trigger = 0.0
        self.Enabled = True
            
    def __str__(self):
        toString = "\tSymbol:{0} weight:{1}\n".format(self.Symbol, self.Weight)
        return toString 
    
    def UpdatePrices(self, data):
        self.Open.append(data[self.Sid].open_price)
        self.High.append(data[self.Sid].high)
        self.Low.append(data[self.Sid].low)
        self.Close.append(data[self.Sid].close_price)
            
    def SetWeight(self):
        upPortion = 0
        dnPortion = 0
        span = len(self.Close)
        for i in range(0, span):
            if (self.Close[i] > self.Open[i]):
                upPortion += (i + 1) * (self.High[i] - self.Low[i])
            else:
                dnPortion += (i + 1) * (self.High[i] - self.Low[i])
        factor = upPortion / (upPortion + dnPortion)
        self.Weight = factor
        
        upPortion = 0
        dnPortion = 0
        if (span > triggerPeriods):
            newStart = span - triggerPeriods
            for i in range(0, triggerPeriods):
                if (self.Close[newStart + i] > self.Open[newStart + i]):
                    upPortion += (i + 1) * (self.High[newStart + i] - self.Low[newStart + i])
                else:
                    dnPortion += (i + 1) * (self.High[newStart + i] - self.Low[newStart + i])
            factor = upPortion / (upPortion + dnPortion)
            self.Trigger = factor
        
        
        
########################################################    
class TradeAtTheOpenSlippageModel(slippage.SlippageModel):
    def __init__(self, fractionOfOpenCloseRange):
        self.fractionOfOpenCloseRange = fractionOfOpenCloseRange

    def process_order(self, trade_bar, order):
        openPrice = trade_bar.open_price
        closePrice = trade_bar.price
        ocRange = closePrice - openPrice
        ocRange = ocRange * self.fractionOfOpenCloseRange
        targetExecutionPrice = openPrice + ocRange
            
        # Create the transaction using the new price we've calculated.
        return slippage.create_transaction(
            trade_bar,
            order,
            targetExecutionPrice,
            order.amount
        )
        
''' Archive
    
    #context.SecMgr.Add("SPY", sid(8554), 1) # SPDR S&P 500 ETF TRUST    
    #context.SecMgr.Add("MDY", sid(12915), 1) # SPDR S&P MIDCAP 400 ETF TRUST
    #context.SecMgr.Add("RSP", sid(24744), 1) # GUGGENHEIM S&P 500 EQUAL WEIGH
    #context.SecMgr.Add("VTI", sid(22739), 1) # VANGUARD TOTAL STOCK MARKET ETF
    #context.SecMgr.Add("VBR", sid(25901), 1) # VANGUARD SMALL-CAP VALUE ETF
    #context.SecMgr.Add("AGG", sid(25485), 1) # ISHARES CORE U.S. AGGREGATE BO


                
            #print("W:{}".format( security.Weight))
            #print("T:{}".format( security.Trigger))

#    for security in context.SecMgr.GetSecurities():
#        if (security.Enabled):
#            if (security.Weight > .55):
#                if (security.Trigger < .25):
#                    order_target_percent(security.Sid, securiyt.Portion)
#            else:
#                order_target_percent(security.Sid, .25)
#            #print("W:{}".format( security.Weight))
#            #print("T:{}".format( security.Trigger))


print("{}:{}".format(security.Symbol, security.Portion))

            #elif (security.Trigger > .90 or security.Weight < .50):
            #    exits[security] = 0


'''
There was a runtime error.

Okay, that makes sense. For minute data would you say that the default slippage model makes sense because the trades are executed in the following minutes and not a full day later?

Made a little headway on a minute bar version. No trading yet, but it looks like the weight and trigger values are in the ballpark. I decided to use the Pandas canned ewma instead of the homebrew weighted moving average, since it is basically the same kinda thing--most recent events are weighted most heavily.

I'll add some comments to the "cryptic matrix alchemy" just to show there's no magic involved.

--Grant

Clone Algorithm
25
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
# https://www.quantopian.com/posts/volatility-bias-up-range-slash-total-range-strategy

import numpy as np
from pytz import timezone
import pandas as pd

trading_freq = 1 # trading frequency, days

def initialize(context):
    context.stocks = [ sid(19654),  # Materials Select Sector SPDR             
                       sid(19655),  # Energy Select Sector SPDR                
                       sid(19656),  # Financial Select Sector SPDR             
                       sid(19657),  # Industrial Select Sector SPDR            
                       sid(19658),  # Technology Select Sector SPDR            
                       sid(19659),  # Consumer Staples Select Sector SPDR      
                       sid(19660),  # Utilities Select Sector SPDR             
                       sid(19661),  # Healthcare Select Sector SPDR            
                       sid(19662),  # Consumer Discretionary Select Sector SPDR
                       sid(25485) ] # ISHARES CORE U.S. AGGREGATE BONDS
    
    context.day_count = -1
    
    context.allocation = -1.0*np.ones_like(context.stocks)

def handle_data(context, data):
    
    # Trade only once per day
    loc_dt = get_datetime().astimezone(timezone('US/Eastern'))
    if loc_dt.hour == 16 and loc_dt.minute == 0:
        context.day_count += 1
        pass
    else:
        return
    
    # Limit trading frequency
    if context.day_count % trading_freq != 0.0:
        return
    
    weight = VolBias(context,42)
    trigger = VolBias(context,4)
    
    # print VolBias(context,42)
    # print VolBias(context,4)
    
    if weight != None and trigger != None:
        record(weight = weight[0], trigger = trigger[0])
    
    # denom = np.sum(allocation)
    # if denom != 0.0:
        # allocation = allocation/np.sum(allocation)
        # 
    # # return if allocation unchanged
    # if np.array_equal(context.allocation,allocation):
        # return
    # 
    # context.allocation = allocation
    # 
    # for stock,percent in zip(context.stocks,allocation):
        # order_target_percent(stock,percent)
        
def VolBias(context,n):
    
    opn = history(60,'1d','open_price').as_matrix(context.stocks)
    close = history(60,'1d','close_price').as_matrix(context.stocks)
    low = history(60,'1d','low').as_matrix(context.stocks)
    high = history(60,'1d','high').as_matrix(context.stocks)
        
    if np.isnan(np.sum(opn)):
        return None
    if np.isnan(np.sum(close)):
        return None
    if np.isnan(np.sum(low)):
        return None
    if np.isnan(np.sum(high)):
        return None
        
    rng = high - low
    
    cls_opn = close - opn
    up_down = np.sign(cls_opn)
    up = np.copy(up_down)
    up[up < 0] = 0
    down = np.copy(up_down)
    down[down > 0] = 0
    
    rng_up = np.multiply(rng,up)
    rng_down = np.multiply(rng,-down)
    
    denom = pd.ewma(rng_up,span=n) + pd.ewma(rng_down,span=n)
    
    return (pd.ewma(rng_up,span=n)/denom)[-1,:]
There was a runtime error.

Anony Mole,
What's the entry and exit logic with the trend variable coding newbie here but v interesting

One possible source of bias is that you've hardcoded the DJIA components, when actually those components change over time. What that might mean is that you've introduced some look-ahead bias into your algorithm, in that you've picked stocks in 2003 that you shouldn't have known would become successful enough to join the DJIA (Cisco, United Health, etc) and likewise you've avoided some stocks which you shouldn't have known would leave the DJIA (Altria, Honeywell, AIG, Citi, GM, Kraft). Ideally for the DJIA component selection to be valid you would have to adjust the DJIA components over time (not too taxing as they don't change frequently, could upload a CSV to Dropbox and import without too much effort).

That said I haven't looked into how much those specific picks drove the results of your latest version.

I think one other thing to consider is whether your slippage model is a reasonable approximation of what will actually happen in live trading. I converted one of your algorithms (the third one you posted in this thread) to trade in minute mode with the default slippage model and configured it to trade at the first possible opportunity - in other words, at the open of the next trading day following the weight and trigger calculations. I ran them side by side for the period 2007-03-09 - 2007-12-31 (I actually ran the daily mode test from 2007-01-01 but due to warm up it doesn't trade until this date, so I delayed the minute mode algorithm accordingly which requires no warm up). I used a relatively small initial budget ($10K).

The performance varied widely even though the weight/trigger calculations and entry/exit parameters were identical (I logged them all). Essentially what happens is that on any given day, the trade price in minute mode trading at the open varies from your "trade at open" slippage model by a range of -1.5% to +0.99%. In this case that means for the first few months of the test, the minute mode algorithm underperforms the daily mode algorithm significantly (average price discrepancy is +0.037% per day in favor of the daily algorithm). The price discrepancy shifts back in favor of the minute mode algorithm for the second half of the test but by then the daily algorithm is already 7% ahead due to the compounded advantage.

I need to clean up the code for the minute mode version and then I'll post it (later today) and I'll also upload the Excel analysis of each individual transaction with price discrepancies detailed.

This has me wondering about having the minute mode algorithm try to trade at the end of the day or near it on the day used to calculate VolBias rather than at the open of the next day, to minimize price drift. I am also wondering about the default slippage model and how realistic it is. Does anyone know how the Quantopian team arrived at the VolumeShareSlippage default parameters?

@Anony, and everyone else

I finally cleared my plate and started looking at your strategy! I started by taking your latest version and ported it to my QuantShim framework. The backtest results don't currently match yours, so I need to work through and find what's causing the discrepancy. That said, the results are approximately the same, so that's a good sign.

My first bit of feedback would be a bit of a worry about the increased trade frequency, why do this? Cutting the initial capital down to 10k (something I could realistically afford for a strategy like this) cut returns from 438% to 190%, on this super-optimized backtest.
I'll give more feedback once I get my port to achieve the same returns as yours. After that, I'll get this running in minute mode.

Clone Algorithm
38
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
# -*- coding: utf-8 -*-  
"""
TL;DR:  
1) jump to the end of this file
2) replace/extend "ExampleFramework" (around line 1601)
3) copy/paste this file to quantopian 
4) backtest
-------------

@summary: An intraday algorithmic trading framework for use with quantopian.com   
Primary use is to support multiple algorithms cooperating

@license: gpl v3

@author: [email protected]  https://PhantomJsCloud.com

@disclaimer:  I'm not a fan of python so sorry that this isn't PEP compliant.


"""

# Import the libraries we will use here
import datetime
import pytz
import math
import numpy
import pandas
import scipy
import scipy.stats
import zipline
import functools
import collections

import sklearn
import sklearn.naive_bayes
#import sklearn.naive_bayes.BernoulliNB
import sklearn.linear_model
import sklearn.ensemble

import talib




is_offline_Zipline = False

#quantopian shims
class WorstSpreadSlippage(slippage.SlippageModel):
    '''will trade at the worst value of the order minute.  high if long, low if short. 
    additionally, supports 'VolumeShareSlippage' functionality, which further biases price/volume'''
    def __init__(this, volume_limit=.25, price_impact=0.1, ohlcWeighted=False):
        this.volume_limit = volume_limit
        this.price_impact = price_impact
        this.ohlcWeighted = ohlcWeighted
        pass
    def __processVolumeShareSlippage(self,event,order, targetPrice):
        '''coppied implementation from VolumeShareSlippage.process_order(), found here: https://github.com/quantopian/zipline/blob/4860a966b3a3102fa80d43f393155e53015cc349/zipline/finance/slippage.py
        modification:  we return the final (price,volume) tuple for our main .process_order() to use, instead of executing the order
        RETURNS: final (price,volume) tuple'''
        ########
        max_volume = self.volume_limit * event.volume

        # price impact accounts for the total volume of transactions
        # created against the current minute bar
        remaining_volume = max_volume - self.volume_for_bar
        if remaining_volume < 1:
            # we can't fill any more transactions
            return (0.0,0)
        # the current order amount will be the min of the
        # volume available in the bar or the open amount.
        cur_volume = int(min(remaining_volume, abs(order.open_amount)))

        if cur_volume < 1:
            return (0.0,0)

        # tally the current amount into our total amount ordered.
        # total amount will be used to calculate price impact
        total_volume = self.volume_for_bar + cur_volume

        volume_share = min(total_volume / event.volume,
                           self.volume_limit)

        simulated_impact = volume_share ** 2 \
            * math.copysign(self.price_impact, order.direction) \
            * targetPrice
        #return create_transaction(
        #    event,
        #    order,
        #    # In the future, we may want to change the next line
        #    # for limit pricing
        #    event.price + simulated_impact,
        #    math.copysign(cur_volume, order.direction)
        return (targetPrice + simulated_impact,int(math.copysign(cur_volume, order.direction)))

    def process_order(this,trade_bar,order):
        
        #worst spread
        if order.amount < 0:
            targetPrice = trade_bar.low
        else:
            targetPrice = trade_bar.high
        #trade at the open
        #targetPrice = trade_bar.open_price

        if this.ohlcWeighted:
            #midpoint, ohlc weighted
            targetPrice = (targetPrice + trade_bar.open_price + trade_bar.high + trade_bar.low + trade_bar.close_price) / 5
            pass


        price, volume = this.__processVolumeShareSlippage(trade_bar,order,targetPrice)
        priceSlippage = trade_bar.close_price - price   
        volumeSlippage = order.amount - volume    

        if price == 0.0 or volume == 0:
            return

        #logger.info(price)
        logger.info("ORDER_COMMITTED: {0} shares {1} @ {2} \n\t  v={8} o={4} h={5} l={6} c={7} \t (WorstSpreadSlippage: vol= -{9} price= {3:.2f})"
                    .format(volume,trade_bar.sid.symbol,price,priceSlippage, trade_bar.open_price, trade_bar.high, trade_bar.low, trade_bar.close_price, trade_bar.volume,volumeSlippage))
        
        return slippage.create_transaction(trade_bar,
                                            order,
                                            price,
                                            order.amount)

class TradeAtTheOpenSlippageModel_Simple(slippage.SlippageModel):
    def __init__(self, fractionOfOpenCloseRange):
        self.fractionOfOpenCloseRange = fractionOfOpenCloseRange

    def process_order(self, trade_bar, order):
        openPrice = trade_bar.open_price
        closePrice = trade_bar.price
        ocRange = closePrice - openPrice
        ocRange = ocRange * self.fractionOfOpenCloseRange
        targetExecutionPrice = openPrice + ocRange
            
        # Create the transaction using the new price we've calculated.
        return slippage.create_transaction(
            trade_bar,
            order,
            targetExecutionPrice,
            order.amount
        )
        
class TradeAtTheOpenSlippage(slippage.SlippageModel):
    '''will trade at the open, good for daily use, kind of not good otherwise.'''
    def __init__(this, volume_limit=.25, price_impact=0.1):
        this.volume_limit = volume_limit
        this.price_impact = price_impact
        pass
    def __processVolumeShareSlippage(self,event,order, targetPrice):
        '''coppied implementation from VolumeShareSlippage.process_order(), found here: https://github.com/quantopian/zipline/blob/4860a966b3a3102fa80d43f393155e53015cc349/zipline/finance/slippage.py
        modification:  we return the final (price,volume) tuple for our main .process_order() to use, instead of executing the order
        RETURNS: final (price,volume) tuple'''
        ########
        max_volume = self.volume_limit * event.volume

        # price impact accounts for the total volume of transactions
        # created against the current minute bar
        remaining_volume = max_volume - self.volume_for_bar
        if remaining_volume < 1:
            # we can't fill any more transactions
            return (0.0,0)
        # the current order amount will be the min of the
        # volume available in the bar or the open amount.
        cur_volume = int(min(remaining_volume, abs(order.open_amount)))

        if cur_volume < 1:
            return (0.0,0)

        # tally the current amount into our total amount ordered.
        # total amount will be used to calculate price impact
        total_volume = self.volume_for_bar + cur_volume

        volume_share = min(total_volume / event.volume,
                           self.volume_limit)

        simulated_impact = volume_share ** 2 \
            * math.copysign(self.price_impact, order.direction) \
            * targetPrice
        #return create_transaction(
        #    event,
        #    order,
        #    # In the future, we may want to change the next line
        #    # for limit pricing
        #    event.price + simulated_impact,
        #    math.copysign(cur_volume, order.direction)
        return (targetPrice + simulated_impact,int(math.copysign(cur_volume, order.direction)))

    def process_order(this,trade_bar,order):
        
        
        #if order.amount < 0:
        #    targetPrice = trade_bar.low
        #else:
        #    targetPrice = trade_bar.high
        targetPrice = trade_bar.open_price

        price, volume = this.__processVolumeShareSlippage(trade_bar,order,targetPrice)
        priceSlippage = trade_bar.close_price - price   
        volumeSlippage = order.amount - volume    

        if price == 0.0 or volume == 0:
            return

        #logger.info(price)
        logger.info("ORDER_COMMITTED: {0} shares {1} @ {2} \n\t  v={8} o={4} h={5} l={6} c={7} \t (TradeAtTheOpenSlippage: vol= -{9} price= {3:.2f})"
                    .format(volume,trade_bar.sid.symbol,price,priceSlippage, trade_bar.open_price, trade_bar.high, trade_bar.low, trade_bar.close_price, trade_bar.volume,volumeSlippage))
        
        return slippage.create_transaction(trade_bar,
                                            order,
                                            price,
                                            order.amount)

    
class CustomSlippage(slippage.SlippageModel):
    ''' allows customizing slippage if desired, though mostly used for logging your order details to the console'''
    def __init__(this, volume_limit=.25, price_impact=0.1, ohlcWeighted=False):
        this.volume_limit = volume_limit
        this.price_impact = price_impact
        this.ohlcWeighted = ohlcWeighted
        pass
    def __processVolumeShareSlippage(self,event,order, targetPrice):
        '''coppied implementation from VolumeShareSlippage.process_order(), found here: https://github.com/quantopian/zipline/blob/4860a966b3a3102fa80d43f393155e53015cc349/zipline/finance/slippage.py
        modification:  we return the final (price,volume) tuple for our main .process_order() to use, instead of executing the order
        RETURNS: final (price,volume) tuple'''
        ########
        max_volume = self.volume_limit * event.volume

        # price impact accounts for the total volume of transactions
        # created against the current minute bar
        remaining_volume = max_volume - self.volume_for_bar
        if remaining_volume < 1:
            # we can't fill any more transactions
            return (0.0,0)
        # the current order amount will be the min of the
        # volume available in the bar or the open amount.
        cur_volume = int(min(remaining_volume, abs(order.open_amount)))

        if cur_volume < 1:
            return (0.0,0)

        # tally the current amount into our total amount ordered.
        # total amount will be used to calculate price impact
        total_volume = self.volume_for_bar + cur_volume

        volume_share = min(total_volume / event.volume,
                           self.volume_limit)

        simulated_impact = volume_share ** 2 * math.copysign(self.price_impact, order.direction) * targetPrice
        #return create_transaction(
        #    event,
        #    order,
        #    # In the future, we may want to change the next line
        #    # for limit pricing
        #    event.price + simulated_impact,
        #    math.copysign(cur_volume, order.direction)
        return (targetPrice + simulated_impact,int(math.copysign(cur_volume, order.direction)))

    def process_order(this,trade_bar,order):
        
        ####worst spread
        #if order.amount < 0:
        #    targetPrice = trade_bar.low
        #else:
        #    targetPrice = trade_bar.high
        ####trade at the open
        #targetPrice = trade_bar.open_price
        ####trade at the close
        targetPrice = trade_bar.close_price

        if this.ohlcWeighted:
            #midpoint, ohlc weighted
            targetPrice = (targetPrice + trade_bar.open_price + trade_bar.high + trade_bar.low + trade_bar.close_price) / 5
            pass


        price, volume = this.__processVolumeShareSlippage(trade_bar,order,targetPrice)
        priceSlippage = trade_bar.close_price - price   
        volumeSlippage = order.amount - volume    

        if price == 0.0 or volume == 0:
            return
        
        
        #construct our pnl once this transaction is comitted (logged below)
        pnl = _g.context.portfolio.pnl + (price * order.amount) - (trade_bar.close_price * order.amount)

        #logger.info(price)
        logger.info("ORDER_COMMITTED: {0} shares {1} @ {2} \n\t  v={8} o={4} h={5} l={6} c={7} \t (Slippage: vol= -{9} price= {3:.2f})\n\tpnl={10}"
                    .format(volume,trade_bar.sid.symbol,price,priceSlippage, trade_bar.open_price, trade_bar.high, trade_bar.low, trade_bar.close_price, trade_bar.volume,volumeSlippage, pnl))
        
        return slippage.create_transaction(trade_bar,
                                            order,
                                            price,
                                            order.amount)

class Logger():
    '''shim for exposing the same logging definitions to visualstudio intelisence'''
    def __init__(this, logErrors=True, logInfos=True, logWarns=True, logDebugs=True):        
        this.__logErrors = logErrors
        this.__logInfos = logInfos
        this.__logWarns = logWarns
        this.__logDebugs = logDebugs
        this.__recordHistory = {}
        this.__lastKnownDay = None
        pass    

    def error(this, message): 
        if not this.__logErrors: return  
        log.error(this.__wrapMessage(message))
        pass
    def info(this, message):
        if not this.__logInfos: return  
        log.info(this.__wrapMessage(message))
        pass
    def warn(this, message):   
        if not this.__logWarns: return  
        log.warn(this.__wrapMessage(message))
        pass
    def debug(this, message):  
        if not this.__logDebugs: return  
        log.debug(this.__wrapMessage(message))
        pass

    def __wrapMessage(this,message):
        this.__trySpamDailyLogs() 
        timestamp = _g.context.framework._getDatetime()
        
        #return str(timestamp) + message
        time = timestamp.strftime("%H:%M")
        
        #if timestamp.second!=0:
        #    time += ":{0}".format(timestamp.second)

        return str(time) + ": " + str(message)
        pass

    def debugAccumulateDaily(this,key,message):
        '''writes the log once a day to avoid spam.  includes timestamp automatically'''
        if not this.__logDebugs: return  
        msg = this.__wrapMessage(message)
        this.__storeToDailyLog(key,msg)

    def debugOnceDaily(this,key,message):
        if not this.__logDebugs: return  
        
        this.__storeToDailyLog(key,message)
        this.__recordHistory[key] = this.__recordHistory[key][0:1]
        this.__trySpamDailyLogs()
        pass
    def __storeToDailyLog(this,key,message):
        if not this.__recordHistory.has_key(key):
            this.__recordHistory[key] = []
        this.__recordHistory[key].append(message)

        pass

    def __trySpamDailyLogs(this):
        if _g.context.framework.thisFrameDay != this.__lastKnownDay:
            #new day, dump our previous logs
            this.__lastKnownDay = _g.context.framework.thisFrameDay   
            for key,values in this.__recordHistory.items():                         
                this.debug("[email protected]{0}=\n{1}".format(key,",".join(values)))
                values[:] = [] #clear it
        pass

    def record(this, name,value, logDaily=False):                    
        this.__trySpamDailyLogs()            
        if(logDaily == True):
            this.__storeToDailyLog(name,"%0.4f" % value)
        record(**{name:value})

    def recordNormalized(this, name,value,baseline=1,subtract=0, logDaily=False):    
        '''normalize values to a 0 to 1 range'''

        if value - subtract == 0 or baseline == 0:
            toRecord = 0
        else:
            toRecord = (value - subtract) / baseline

        this.record(name,toRecord,logDaily=logDaily)

    #def getLastRecord(this,name):
    #    '''returns the last recorded value.  only exists if doing daily
    #    outputs, and during the day.  returns None if name not found'''
    #    return this.__recordHistory.get(name)
    pass

global logger
logger = Logger() #(logDebugs=False)

class Shims():
    '''SHIM OF QUANTOPIAN INTERNAL REPRESENTATION.  here for intelisence only.  you SHOULD NOT actually instantiate these.'''
    
    class Position:
        '''
        The position object represents a current open position, and is contained inside the positions dictionary. 
        For example, if you had an open AAPL position, you'd access it using context.portfolio.positions[sid(24)]. 
        The position object has the following properties:
            amount = 0 #Integer: Whole number of shares in this position.
            cost_basis = 0.0 #Float: The volume-weighted average price paid per share in this position.
            last_sale_price = 0.0 #Float: Price at last sale of this security.
            sid = 0 #Integer: The ID of the security.
        '''
        def __init__(this):
            this.amount = 0 #Integer: Whole number of shares in this position.
            this.cost_basis = 0.0 #Float: The volume-weighted average price paid per share in this position.
            this.last_sale_price = 0.0 #Float: Price at last sale of this security.
            this.sid = 0 #Integer: The ID of the security.

    class Context():
        def __init__(this , portfolio=zipline.protocol.Portfolio()): #, tradingAlgorithm = zipline.TradingAlgorithm()):
            this.portfolio = portfolio
            #this.tradingAlgorithm = tradingAlgorithm
            pass
        pass

    


    

    class _TradingAlgorithm_QuantopianShim:
        '''shim of zipline.TradingAlgorithm for use on quantopian '''
        def __init__(this):
            #this.logger = Shims._Logger()
            #this.logger = log
            pass
        

        def order(this,sid,amount,limit_price=None, stop_price=None):
            '''
            Places an order for the specified security of the specified number of shares. Order type is inferred from the parameters used. If only sid and amount are used as parameters, the order is placed as a market order.
            Parameters
            sid: A security object.
            amount: The integer amount of shares. Positive means buy, negative means sell.
            limit_price: (optional) The price at which the limit order becomes active. If used with stop_price, the price where the limit order becomes active after stop_price is reached.
            stop_price: (optional) The price at which the order converts to a market order. If used with limit_price, the price where the order converts to a limit order.
            Returns
            An order id.
            '''
            if sid is Security:
                security = sid
            else:
                security = this.context.framework.allSecurities[sid]
            #logger.info("{0} ordering {1}".format(security.qsec,amount))
            orderId = order(security.qsec,amount,limit_price,stop_price)
            return orderId
            pass

        def order_percent(self, sid, percent, limit_price=None, stop_price=None):
            """
            Place an order in the specified security corresponding to the given
            percent of the current portfolio value.

            Note that percent must expressed as a decimal (0.50 means 50\%).
            """
            value = self.context.portfolio.portfolio_value * percent
            return self.order_value(sid, value, limit_price, stop_price)

        def order_target(self, sid, target, limit_price=None, stop_price=None):
            """
            Place an order to adjust a position to a target number of shares. If
            the position doesn't already exist, this is equivalent to placing a new
            order. If the position does exist, this is equivalent to placing an
            order for the difference between the target number of shares and the
            current number of shares.
            """
            if sid in self.context.portfolio.positions:
                current_position = self.context.portfolio.positions[sid].amount
                req_shares = target - current_position
                return self.order(sid, req_shares, limit_price, stop_price)
            else:
                return self.order(sid, target, limit_price, stop_price)

        def order_target_value(self, sid, target, limit_price=None,
                               stop_price=None):
            """
            Place an order to adjust a position to a target value. If
            the position doesn't already exist, this is equivalent to placing a new
            order. If the position does exist, this is equivalent to placing an
            order for the difference between the target value and the
            current value.
            """
            if sid in self.context.portfolio.positions:
                current_position = self.context.portfolio.positions[sid].amount
                current_price = self.context.portfolio.positions[sid].last_sale_price
                current_value = current_position * current_price
                req_value = target - current_value
                return self.order_value(sid, req_value, limit_price, stop_price)
            else:
                return self.order_value(sid, target, limit_price, stop_price)

        def order_target_percent(self, sid, target, limit_price=None,
                                 stop_price=None):
            """
            Place an order to adjust a position to a target percent of the
            current portfolio value. If the position doesn't already exist, this is
            equivalent to placing a new order. If the position does exist, this is
            equivalent to placing an order for the difference between the target
            percent and the current percent.

            Note that target must expressed as a decimal (0.50 means 50\%).
            """
            if sid in self.context.portfolio.positions:
                current_position = self.context.portfolio.positions[sid].amount
                current_price = self.context.portfolio.positions[sid].last_sale_price
                current_value = current_position * current_price
            else:
                current_value = 0
            target_value = self.context.portfolio.portfolio_value * target

            req_value = target_value - current_value
            return self.order_value(sid, req_value, limit_price, stop_price)

        pass

    #class _TradingAlgorithm_ZiplineShim(zipline.TradingAlgorithm):
    #    '''auto-generates a context to use'''
    #    def initialize(this):
    #        #delay initialize until start of first handle-data, so our
    #        #portfolio object is available
    #        #this.__isInitialized = False;
    #        this.context = Shims.Context()
    #        this.context.tradingAlgorithm = this            
    #        #this.context.portfolio = this.portfolio
    #        pass

    #    def handle_data(this,data):      
    #        this.context.portfolio = this.portfolio
    #        #if not this.__isInitialized:
    #        #    this.__isInitialized=True
    #        #    this.context.portfolio=this.portfolio
                
    #        this.context.framework._update(data)
    #        pass
    #    pass

class FrameHistory:
    def __init__(this,parent,framework, data):
        this.parent = parent
        this.framework = framework
        this.state = []
        this.isActive = this.parent.isActive
        #this.maxHistoryFrames = this.framework.maxHistoryFrames
        #assert(this.framework.simFrame == this.parent.simFrame, "parent frame
        #does not match")
        
        this.initialize(data)
    
    def initialize(this, data):
        '''overridable'''
        logger.error("FrameHistory.initialize() invoked.  You should override this method.")
        pass

    def constructFrameState(this,data):
        '''override and return the frame state, this will be prepended to history
        if you return NONE, the frame state (history) is not modified.'''   
        logger.error("FrameHistory.constructFrameState() invoked.  You should override this method.")             
        pass

    def _update(this,data):
        this.isActive = this.parent.isActive
        if not this.isActive:
            return

        

        currentState = this.constructFrameState(data)
        if(currentState != None):
            currentState.datetime = this.framework._getDatetime()
            currentState.simFrame = this.framework.simFrame

            this.state.insert(0,currentState)
            del this.state[this.framework.maxHistoryFrames:]

class StrategyPosition:
    '''allows two or more stratgies to controll their own positions (orders) for securities they care about, 
    without interfering with the orders of other strategies.

    To use:   each strategy should set security.myStrategyPositon.targetCapitalSharePercent, which is a percentage of your entire portfolio's value
    then execute the order (and/or rebalance) by invoking security.myStrategyPosition.processOrder()
    '''

    def __init__(this, security, strategyName):            
        this._security = security
        this._strategyName = strategyName
        this._lastOrderId = 0
        this._lastStopOrderId = 0
        this._currentCapitalSharePercent = 0.0
        this._currentShares = 0
        #for the last trade roundtrip, the aproximate returns.  set every time our percent changes to zero
        this._lastRoundtripReturns = 0.0
        #this is editable
        this.targetCapitalSharePercent = 0.0
        #price when we decided to order, not actually the fulfillment price
        this.__lastOrderPrice = 0.0
        this.__currentPeakGains = 0.0
        this.__currentPeakGainsDecay = 0.0
        this._currentReturns = 0.0 #returns of current open position. 
        this._totalTrades = 0 #total trades we execute via this strategyPosition.  note that due to partial fills, this may be less than actual trades

    def processOrder(this, data, rebalanceThreshholdPercent=0.05, maxLosses=None, maxGainsAdditionalDrawdown=None, maxGainsDecay=0.01): #, OBSOLETE_stopLimitPercent=0.0, OBSOLETE_momentumStopLimit = True, OBSOLETE_decayMomentum = 0.001):
        ''' set rebalanceThreshholdPercent to zero (0.0) to cause the position to readjust even if the targetPercentage doesn't change.   this is useful for reinvesting divideds / etc
        but is set to 0.05 (5 percent) so we don't spam orders 
        
        maxLosses:  close if our open position suffers a loss of this percent or more
        maxGainsAdditionalDrawdown : close if our open position's gains suffer a decrease of this+maxLosses or more.
        maxGainsDecay : over time this will reduce the acceptable gains drawdown (specified by maxGainsAdditionalDrawdown) so that on long-running gains we don't incur such a large drawdown before closing.
        '''
        #if momentumStopLimit == True (the default) we will stopLimitPercent based on the peak gains, not based on the original purchase price (this is generally a good ideas as it will maximize your gains)
        #decayMomentum : = if == 0.01 and using momentumStopLimit==True, we will decay the position's survival chances by 1% per tick until it's finally closed.
        
        if this._currentCapitalSharePercent == 0.0 and this.targetCapitalSharePercent == 0.0:
            #no work to do
            return 0



        currentPrice = data[this._security.qsec].close_price
        
        if this._currentCapitalSharePercent == this.targetCapitalSharePercent and this._currentCapitalSharePercent != 0.0:
            #update current returns
            this._currentReturns = (currentPrice - this.__lastOrderPrice) / this.__lastOrderPrice * math.copysign(1.0,this._currentCapitalSharePercent)
        else:
            #target is different so reset our returns as we are about to change our order
            this._currentReturns = 0.0


        if this._currentCapitalSharePercent == this.targetCapitalSharePercent and maxGainsAdditionalDrawdown != None:
            ##handle maxGains stoplimits
            gainsPercent = this._currentReturns - this.__currentPeakGainsDecay
            #if gainsPercent < -maxLosses:
            #    #loosing, so close out
            #    logger.debug("loosing, so close out.  gainsPercent={0}, maxLosses={1}".format(gainsPercent, maxLosses))
            #    this.targetCapitalSharePercent = 0.0 
            #else:

            if this._currentReturns > this.__currentPeakGains:
                this.__currentPeakGains = this._currentReturns
                this.__currentPeakGainsDecay = 0.0 #reset decay 
            else:
                #need to see if our gain exceed our stoplimitGains threshhold
                gainsFloorThreshhold = this.__currentPeakGains * maxGainsAdditionalDrawdown
                if gainsPercent < gainsFloorThreshhold:
                    lossesFromPeak = this.__currentPeakGains - gainsPercent
                    if maxLosses != None and lossesFromPeak < maxLosses:
                        #we are not yet exceeding maxLosses (from our peak) so don't close out yet
                        logger.debug("we are not yet exceeding maxLosses (from our peak) so don't close out yet.  \t {0} @ {1}, gains={2}".format(this._security.symbol,currentPrice,this._currentReturns))
                        pass
                    else:
                        #loosing from our peak, so close out
                        logger.debug("loosing from our peak, so close out.  gainsPercent={0:.4f}, \t gainsFloorThreshhold={1:.4f}, \t  lossesFromPeak={2:.4f}, \t  maxLosses={3:.4f}  \t this._currentReturns={4:.4f}".format(gainsPercent, gainsFloorThreshhold, lossesFromPeak, maxLosses,this._currentReturns))
                        this.targetCapitalSharePercent = 0.0 

                this.__currentPeakGainsDecay += (this.__currentPeakGains * maxGainsDecay)
        else:
            this.__currentPeakGains = 0.0
            this.__currentPeakGainsDecay = 0.0

        if this._currentCapitalSharePercent == this.targetCapitalSharePercent and this._currentCapitalSharePercent != 0.0:
            #handle maxlosses stoplimit
            if maxLosses != None and this._currentReturns < -maxLosses:
                logger.debug("maxlosses stoplimit.  this._currentReturns={0}, maxLosses={1}".format(this._currentReturns, maxLosses))
                this.targetCapitalSharePercent = 0.0


           

        if this.targetCapitalSharePercent == 0.0 and this._currentCapitalSharePercent != 0.0:
            #record our expected PnL
            this._lastRoundtripReturns = this._currentReturns

        this._currentCapitalSharePercent = this.targetCapitalSharePercent
        
        
           
        #determine value of percent
        targetSharesValue = this._security.framework.context.portfolio.portfolio_value * this._currentCapitalSharePercent
        targetSharesTotal = int(math.copysign(math.floor(abs(targetSharesValue / currentPrice)),targetSharesValue))
        
        targetSharesDelta = targetSharesTotal - this._currentShares

        if targetSharesTotal != 0:
            if abs(targetSharesDelta / (targetSharesTotal * 1.0)) < rebalanceThreshholdPercent:
                #logger.debug("{0} ORDER SKIPPED! {1} (change to small) : {2} + {3} => {4} shares".format(this.strategyName,this.security.symbol, this.currentShares, targetSharesDelta, targetSharesTotal))          
                #our position change was too small so we skip rebalancing
                return

        #do actual order
        if(abs(targetSharesDelta) >= 1): #can not perform an order on less than 1 share
            ####cancel previous open order, if any  #doesn't really work, as even when canceling, some shares may be filled so you'll be left in an uncomplete state
            ###lastOrder = get_order(this.lastOrderId)
            ###unfilled = lastOrder.amount - l
            ###cancel_order(this.lastOrderId)
            logger.info("{0} order {1} : {2} + {3} => {4} shares  \t \t decisionPrice={5} ".format(this._strategyName,this._security.symbol, this._currentShares, targetSharesDelta, targetSharesTotal,currentPrice))          
            this._lastOrderId = this._security.framework.tradingAlgorithm.order(this._security.sid,targetSharesDelta,None,None)
            this._currentShares = targetSharesTotal
            this.__lastOrderPrice = currentPrice
            this._totalTrades += 1
            this._security.framework._totalTrades += 1
            
            return this._lastOrderId
        else:
            return 0

class Security:
    isDebug = False


    class QSecurity:
        '''
        Quantopian internal security object
        If you have a reference to a security object, there are several properties that might be useful:
            sid = 0 #Integer: The id of this security.
            symbol = "" #String: The ticker symbol of this security.
            security_name = "" #String: The full name of this security.
            security_start_date = datetime.datetime() #Datetime: The date when this security first started trading.
            security_end_date = datetime.datetime() #Datetime: The date when this security stopped trading (= yesterday for securities that are trading normally, because that's the last day for which we have historical price data).
        '''
        def __init__(this):
            this.sid = 0 #Integer: The id of this security.
            this.symbol = "" #String: The ticker symbol of this security.
            this.security_name = "" #String: The full name of this security.
            this.security_start_date = datetime.datetime(1990,1,1) #Datetime: The date when this security first started trading.
            this.security_end_date = datetime.datetime(1990,1,1) #Datetime: The date when this security stopped trading (= yesterday for securities that are trading normally, because that's the last day for which we have historical price data).
    
    

    def __init__(this,sid, framework):
        this.sid = sid  
        this.isActive = False
        this.framework = framework
        this.security_start_date = datetime.datetime.utcfromtimestamp(0)
        this.security_end_date = datetime.datetime.utcfromtimestamp(0)
        this.simFrame = -1
        this.security_start_price = 0.0
        this.security_end_price = 0.0
        #this.daily_open_price = [0.0]
        #this.daily_close_price = [0.0]
        this.symbol = "??? Not yet active so symbol not known"
        
        
    def getCurrentPosition(this):
        if this.simFrame == -1:
            return Shims.Position()
        return this.framework.context.portfolio.positions[this.qsec]

    def update(this,qsec, data):
        '''qsec is only given when it's in scope, and it can actually change each timestep 
        what it does:
        - construct new state for this frame
        - update qsec to most recent (if any)
        '''
        #update our tickcounter, mostly for debug
        this.simFrame = this.framework.simFrame
        #assert(this.simFrame >= 0,"security.update() frame not set")

        
        
        #update qsec to most recent (if any) 67
        this.qsec = qsec
        if qsec:
            this.isActive = True
            this.symbol = qsec.symbol
            #assert(qsec.sid == this.sid,"security.update() sids do not match")
            
            if this.security_start_price == 0.0:
                this.security_start_price = data[this.sid].close_price
            this.security_end_price = data[this.sid].close_price

            this.security_start_date = qsec.security_start_date
            this.security_end_date = qsec.security_end_date
        else:
            this.isActive = False

        #try:
        #    this.daily_close_price =
        #    this.framework.daily_close_price[this.qsec]
        #    this.daily_open_price = this.framework.daily_open_price[this.qsec]
        #except:
        #    this.daily_close_price = []
        #    this.daily_open_price = []

        #if len(this.daily_close_price) == 0 or len(this.daily_open_price) ==
        #0:
        #    this.isActive = False
class FrameworkBase():
    def __init__(this, context, data, maxHistoryFrames=60): #5 days of history
        this.maxHistoryFrames = maxHistoryFrames
        this.__isFirstTimestepRun = False
        this.context = context
        this.tradingAlgorithm = Shims._TradingAlgorithm_QuantopianShim() #prepopulate to allow intelisence
        this.tradingAlgorithm = context.tradingAlgorithm
        this.simFrame = -1 #the current timestep of the simulation
        this.framesToday = -1 #number of frames executed today
        
        this.allSecurities = {} #dictionary of all securities, including those not targeted
        this.activeSecurities = {}

        this.thisFrameDay = 0
        this.lastFrameDay = 0

        this._totalTrades = 0 #total trades we execute via all strategyPositions.  note that due to partial fills, this may be less than actual trades

        this.isIntradayRunDetected = False #if we are running in intraday, this will be set to true on frame 2.  the 2nd bar will be in the same day as the first bar.  no better way to detect unfortunately.

        #for storing quantopian history
        #this.daily_close_price = pandas.DataFrame()
        #this.daily_open_price = pandas.DataFrame()
        
        this._initialize(data)

        pass
    def ensureMinHistory(this, minFrames):
        '''increases the history frames if the current is less than your required min.  
        this is a good way to set your history, as too much history will slow down your sim, and can crash it due to out-of-memory'''

        if this.maxHistoryFrames < minFrames:
            this.maxHistoryFrames = minFrames      
    
    def _initialize(this, data):
        '''starts initialiation of the framework
        do not override this, or any other method starting with an underscore.
        methods without an underscore prefix can and should be overridden.'''
        #do init here
        this.initialize(data)        
        pass

    def initialize(this, data):
        '''override this to do your init'''
        logger.error("You should override FrameworkBase.initialize()")
        pass


    def initializeFirstUpdate(this,data):
        '''override this.  called the first timestep, before update.  
        provides access to the 'data' object which normal .initialize() does not'''
        logger.error("You should override FrameworkBase.initializeFirstUpdate()")
        pass

    def _update(this,data):

        '''invoked by the tradingAlgorithm shim every update.  internally we will call abstract_update_timestep_handle_data()
        DO NOT OVERRIDE THIS OR ANY METHODS STARTING WITH AN UNDERSCORE
        override methods without underscores.
        '''
        
        #frame updates
        #this.data = data

        this.simFrame+=1        
        
        this.lastFrameDay = this.thisFrameDay
        this.thisFrameDay = this._getDatetime().day

        
        #supdating our history once per day
        if(this.thisFrameDay != this.lastFrameDay):
            #only update this once per day, hopefully improving performance...
            #this.daily_close_price = history(bar_count=180, frequency='1d',
            #field='close_price')
            #this.daily_open_price = history(bar_count=180, frequency='1d',
            #field='open_price')
            this.framesToday = 0
        else:
            this.framesToday += 1
            this.isIntradayRunDetected = True

        this.__updateSecurities(data)
        

        if not this.__isFirstTimestepRun:
            this.__isFirstTimestepRun = True
            this.initializeFirstUpdate(data)

        this.update(data)
        pass

    def update(this,data):
        '''override and update your usercode here'''
        logger.error("You should override FrameworkBase.update()")
        pass

    def __updateSecurities(this,data):
        '''get all qsecs from data, then update the targetedSecurities accordingly'''
        #logger.debug("FrameworkBase.__updateSecurities() start.
        #allSecLength={0}".format(len(this.allSecurities)))
        #convert our data into a dictionary
        currentQSecs = {}
        newQSecs = {}
        for qsec in data:            
            #if online, qsec is a securities object
            sid = qsec.sid      
            
            #logger.debug("FrameworkBase.__updateSecurities() first loop, found
            #{0}, sid={1}.  exists={2}".format(qsec,
            #sid,this.allSecurities.has_key(sid) ))

            currentQSecs[sid] = qsec
            #determine new securities found in data
            if not this.allSecurities.has_key(sid):
                logger.debug("FrameworkBase.__updateSecurities() new security detected.  will construct our security object for it: {0}".format(qsec))
                newQSecs[sid] = qsec


        #construct new Security objects for our newQSecs
        for sid, qsec in newQSecs.items():            
            #assert(not
            #this.allSecurities.has_key(sid),"frameworkBase.updateSecurities
            #key does not exist")
            #logger.debug("FrameworkBase.__updateSecurities() new security
            #found {0}".format(qsec))
            this.allSecurities[sid] = this._getOrCreateSecurity(qsec, data)

        newQSecs.clear()


        #update all security objects, giving a null qsec if one doesn't exist
        #in our data dictionary
        for sid, security in this.allSecurities.items():
            qsec = currentQSecs.get(sid)
            security.update(qsec, data)

        ## determine active securities set.
        this.activeSecurities.clear()
        for sid,security in this.allSecurities.items():
            if not security.isActive:
                #logger.debug("FrameworkBase.__updateSecurities() NOT ACTIVE
                #{0}".format(security.qsec))
                continue
            #logger.debug("FrameworkBase.__updateSecurities() ACTIVE
            #{0}".format(security.qsec))
            this.activeSecurities[sid] = security
            pass

        pass

    def initializeSecurity(this,security, data):
        '''override to do custom init logic on each security. 
        if you wish to use your own security, return it (it will replace the existing)'''
        logger.error("You should override FrameworkBase.initializeSecurity()")
        pass       
             
    def _getOrCreateSecurities(this,qsecArray, data):
        '''pass in an array of quantopian sid/sec tuples  (ex:  [(24,sid(24)),(3113,sid(3113))]) 
        and returns an array of unique security objects wrapping them.   duplicate sids are ignored'''

        securities = {}

        for qsec in qsecArray:            
            security = this._getOrCreateSecurity(qsec, data)
            securities[security.sid] = security
            pass

        return securities.values()

    def _getOrCreateSecurity(this, qsec, data):
        '''pass in a quantopian sec (ex:  sid(24)) and returns our security object wrapping it
        if the security object
        '''
        
        sid = qsec.sid
        if this.allSecurities.has_key(sid):
            return this.allSecurities[sid]

        #does not exist, have to create
        newSecurity = Security(sid,this)
        #new, so do our framework's custom init logic on this security
        maybeNewSec = this.initializeSecurity(newSecurity, data)
        if maybeNewSec is not None:
            #framework replaced newSec with a different sec
            newSecurity = maybeNewSec
                
        this.allSecurities[sid] = newSecurity
        
        return newSecurity
        pass


    def _getDatetime(this):
        '''returns current market time, using US/Eastern timezone'''
        #if is_offline_Zipline:
        #    if len(this.allSecurities) == 0:
        #        #return datetime.datetime.fromtimestamp(0,pytz.UTC)
        #        return
        #        pandas.Timestamp(datetime.datetime.fromtimestamp(0,pytz.UTC)).tz_convert('US/Eastern')
        #    else:
        #        assert(False,"need to fix this to return something valid.  all
        #        securities isn't good enough.  probably search for first
        #        active")
        #        return this.allSecurities.values()[0].datetime
        #else:
        #    return get_datetime()
        #pass
        return pandas.Timestamp(pandas.Timestamp(get_datetime()).tz_convert('US/Eastern'))
#entrypoints

def handle_data(context=Shims.Context(),data=pandas.DataFrame()):   
    '''update method run every timestep on quantopian'''
    
    #try: 
    if context.firstFrame:
        #'''init on our first frame'''
        context.firstFrame = False
        context.tradingAlgorithm = Shims._TradingAlgorithm_QuantopianShim()
        context.tradingAlgorithm.context = context
        context.framework = constructFramework(context,data)
        
    
    context.framework._update(data)
    #except Exception,e:
    #    print "Caught:",e

    pass

class Global():
    pass
global _g
_g = Global()



def initialize(context=Shims.Context()):
    '''initialize method used when running on quantopian'''
    context.firstFrame = True 
    
    _g.context = context
    #context.spy = sid(8554) #SPY
    ########## SET UNIVERSE
    #if you need set universe, do it here (note that doing this slows the algo
    #considerably)
    #set_universe(universe.DollarVolumeUniverse(floor_percentile=90.0,ceiling_percentile=100.0))
    #context.universe = [#sid(698)         #BA
    #    #sid(8554) #SPY
    #    #sid(27098) #ISE

    #    ####################### 9 sector etfs
    #    sid(19662) # XLY Consumer Discrectionary SPDR Fund
    #    ,sid(19656) # XLF Financial SPDR Fund
    #    ,sid(19658) # XLK Technology SPDR Fund
    #    ,sid(19655) # XLE Energy SPDR Fund
    #    ,sid(19661) # XLV Health Care SPRD Fund
    #    ,sid(19657) # XLI Industrial SPDR Fund
    #    ,sid(19659) # XLP Consumer Staples SPDR Fund
    #    ,sid(19654) # XLB Materials SPDR Fund
    #    ,sid(19660) # XLU Utilities SPRD Fund
    #    ]

    #aprox 200 SPY constituents from fetcher
    #fetch_csv(
    #   "https://googledrive.com/host/0BwZ2bMDOKaeDYWYzYzgxNDYtNmQyYi00ZDk5LWE3ZTYtODQ0ZDAzNTBkY2M4/trading/SP500-20131001.csv",
    #    pre_func=preview,
    #    date_column='date',
    #    universe_func=(my_universe))
    #aprox 90 hardcoded SPY constituents
    #my_static_universe(context) 

    ########## COMMISSION
    #use top to decrease uncertainty when testing algorithms
    #set_commission(commission.PerShare(cost=0.0))
    #set_commission(commission.PerShare(cost=0.005, min_trade_cost=1.00)) #IB
    #fixed commission model
    #set_commission(commission.PerShare(cost=0.013, min_trade_cost=1.3)) #more
    #agressive...
    
    ########## SLIPPAGE
    #use top to decrease uncertainty when testing algorithms
    #set_slippage(slippage.FixedSlippage(spread=0.00))
    #set_slippage(slippage.FixedSlippage(spread=0.01))
    #set_slippage(WorstSpreadSlippage())
    #set_slippage(CustomSlippage(1.0,0.0))

    ############# Anony values
    set_commission(commission.PerTrade(cost=1.0))
    set_slippage(TradeAtTheOpenSlippageModel_Simple(0.1))

##############  USERCODE BELOW.  EDIT BELOW THIS LINE
##############  USERCODE BELOW.  EDIT BELOW THIS LINE
##############  USERCODE BELOW.  EDIT BELOW THIS LINE


class BBTechnicalIndicators(FrameHistory):
    '''technical indicators relating to bollinger bands'''
    class State:
        '''State recorded for each frame (minute).  number of frames history we store is determined by framework.maxHistoryFrames'''
        def __init__(this,parent, security, data):
            this.parent = parent
            this.security = security
            this.history = this.parent.state

            bb = this.parent.bbands_data[this.security.sid]
            #will be NaN if not enough period
            this.upperLimit = bb[0]
            this.line = bb[1]
            this.lowerLimit = bb[2]
            #see https://www.tradingview.com/stock-charts-support/index.php/Bollinger_Bands_%25B_(%25B)
            this.percentB = (this.security.standardIndicators.state[0].close_price - this.lowerLimit) / (this.upperLimit - this.lowerLimit)
            #see https://www.tradingview.com/stock-charts-support/index.php/Bollinger_Bands_Width_(BBW)
            this.bbw = (this.upperLimit - this.lowerLimit) / this.line
            #track slope of %B, to determine if rising (positive) or falling (negative)
            if len(this.history) > 0:
                this.percentBSlope = (this.percentB - this.history[0].percentB)
                this.bbwSlope = (this.bbw - this.history[0].bbw)
                this.percentBPercentile = scipy.stats.percentileofscore([state.percentB for state in this.history],this.percentB,"mean") / 100.0
                this.bbwPercentile = scipy.stats.percentileofscore([state.bbw for state in this.history],this.bbw,"mean") / 100.0 
                this.lineSlope = (this.line - this.history[0].line)
            else:
                this.percentBSlope = 0.0
                this.bbwSlope = 0.0
                this.percentBPercentile = 0.5
                this.bbwPercentile = 0.5
                this.lineSlope = 0.0

            #track momentum
            if this.percentB > 0.8:
                if len(this.history) > 0:
                    this.upperMomentumTicks = this.history[0].upperMomentumTicks + 1
                else:
                    this.upperMomentumTicks = 1
            else:
                this.upperMomentumTicks = 0            
            if this.percentB < 0.2:
                if len(this.history) > 0:
                    this.lowerMomentumTicks = this.history[0].lowerMomentumTicks + 1
                else:
                    this.lowerMomentumTicks = 1
            else:
                this.lowerMomentumTicks = 0





            #logger.debug(" bb for {0} is {1}".format(this.security.symbol, bb));
            
            #logger.recordNormalized("upperLimit",this.upperLimit,this.security.security_start_price)
            #logger.recordNormalized("line",this.line,this.security.security_start_price)
            #logger.recordNormalized("lowerLimit",this.lowerLimit,this.security.security_start_price)

            #logger.record("upperBar",1.0)
            #logger.record("lowerBar",0.0)
            #logger.record("upperApproach",0.8)
            #logger.record("lowerApproach",0.2)
            #logger.record("percentB",this.percentB);

        def __repr__(this):
            return "{0} @ {1} BBANDS l={2:.2f} \t upper={3:.2f} lower={4:.2f}".format(this.security.symbol, this.datetime, this.line, this.upperLimit, this.lowerLimit)


    def initialize(this, data):
        this.bbands = ta.BBANDS(timeperiod=20,nbdevup=2, nbdevdn=2,matype=0) #output: Dictionary of sid to tuples, where each tuple is three floats: (upperLimit, line, lowerLimit).
        this.bbands_data = this.bbands(data)
        pass
    
    def constructFrameState(this,data):
        #logger.debug("BBTechnicalIndicators.constructFrameState")
        currentState = BBTechnicalIndicators.State(this, this.parent, data)
        return currentState

class StandardIndicators(FrameHistory):
    '''common technical indicators that we plan to use for any/all strategies
    feel free to extend this, or use as a reference for constructing specialized technical indicators'''
    class State:
        '''State recorded for each frame (minute).  number of frames history we store is determined by framework.maxHistoryFrames'''
        def __init__(this,parent, security, data):
            this.parent = parent
            this.security = security
            this.history = this.parent.state

            #preset for proper intelisence
            this.datetime = datetime.datetime.now()
            this.open_price = 0.0
            this.close_price = 0.0
            this.high = 0.0
            this.low = 0.0
            this.volume = 0

            #this.mavg3 = 0.0
            #this.mavg7 = 0.0
            #this.mavg15 = 0.0
            #this.mavg30 = 0.0
            #this.mavg45 = 0.0
            #this.mavg60 = 0.0

            #this.stddev3 = 0.0
            #this.stddev7 = 0.0
            #this.stddev15 = 0.0
            #this.stddev30 = 0.0
            #this.stddev45 = 0.0
            #this.stddev60 = 0.0

            this.datetime = data[this.security.qsec].datetime
            this.open_price = data[this.security.qsec].open_price
            this.close_price = data[this.security.qsec].close_price
            this.high = data[this.security.qsec].high
            this.low = data[this.security.qsec].low
            this.volume = data[this.security.qsec].volume
                        
            
            #mavg for last x minutes
            #this.mavg3 = numpy.mean([state.close_price for state in
            #this.history[0:3]])
            #this.mavg7 = numpy.mean([state.close_price for state in
            #this.history[0:7]])
            #this.mavg15 = numpy.mean([state.close_price for state in
            #this.history[0:15]])
            #this.mavg30 = numpy.mean([state.close_price for state in
            #this.history[0:30]])
            #this.mavg45 = numpy.mean([state.close_price for state in
            #this.history[0:45]])
            #this.mavg60 = numpy.mean([state.close_price for state in
            #this.history[0:60]])

            #this.stddev3 = numpy.std([state.close_price for state in
            #this.history[0:3]])
            #this.stddev7 = numpy.std([state.close_price for state in
            #this.history[0:7]])
            #this.stddev15 = numpy.std([state.close_price for state in
            #this.history[0:15]])
            #this.stddev30 = numpy.std([state.close_price for state in
            #this.history[0:30]])
            #this.stddev45 = numpy.std([state.close_price for state in
            #this.history[0:45]])
            #this.stddev60 = numpy.std([state.close_price for state in
            #this.history[0:60]])

            if len(this.history) < 1:                
                this.returns = 0.0
                this.returns_median_abs = 0.0
            else:
                #always returns compared to last timestep
                this.returns = (this.close_price - this.history[0].close_price) / this.history[0].close_price
                if len(this.history) == 1:
                    this.returns_median_abs = abs(this.returns)
                else:
                    this.returns_median_abs = numpy.median([abs(state.returns) for state in this.history])

            try:                
                #when in intraday mode, stores cumulative returns through the day
                this.returns_today = data[this.security.qsec].returns()
            except:
                this.framework.logger.error("{0} unable to obtain returns()  setting returns to zero  open={1}.  close = {2}".format(this.parent.qsec, this.open_price, this.close_price))
                this.returns_today = 0.0
            pass

            #daily accumulations
            if this.security.framework.thisFrameDay != this.security.framework.lastFrameDay or len(this.history) < 1:
                this.open_price_today = this.open_price
                #if len(this.history) < 1:
                    
                #    this.open_price_yesterday = this.open_price_today
                #    this.close_price_yesterday = this.close_price
                #    this.returns_yesterday = this.returns_today
                ##new day, so record our start of day values
                #else:
                #    this.open_price_yesterday =
                #    this.history[0].open_price_today
                #    this.close_price_yesterday = this.history[0].close_price
                #    this.returns_yesterday = this.history[0].returns_today
            else:
                this.open_price_today = this.history[0].open_price_today
                #this.open_price_yesterday =
                #this.history[0].open_price_yesterday
                #this.close_price_yesterday =
                #this.history[0].close_price_yesterday
                #this.returns_yesterday = this.history[0].returns_yesterday

        def __repr__(this):
            return "{0} @ {1} c={0}".format(this.security.symbol, this.datetime, this.close_price)

    def initialize(this, data):
        pass
    
    def constructFrameState(this,data):
        #logger.debug("StandardTechnicalIndicators.constructFrameState")
        currentState = StandardIndicators.State(this, this.parent, data)
        return currentState


class DailyTechnicalIndicators(FrameHistory):
    '''standard technical indicators for the entire day
    for daily history.   the .state[] history does not include the current day, only previous days'''
    class State:
        '''State recorded for each previous day.  number of frames history we store is determined by framework.maxHistoryFrames'''
        def __init__(this,parent, security, data):
            this.parent = parent
            this.security = security
            this.history = this.parent.state



            #preset for proper intelisence
            this.datetime = datetime.datetime.now()


            #setting these to default to yesterday's value so that for the
            #first day of our simulation we get reasonable values
            this.open_price = data[this.security.qsec].mavg(1)
            this.close_price = this.open_price
            #this.high = 0.0
            #this.low = 0.0
            #this.volume = 0

            #this.mavg3 = this.open_price
            #this.mavg7 = this.open_price
            #this.mavg15 = this.open_price
            #this.mavg30 = this.open_price
            #this.mavg45 = this.open_price
            #this.mavg60 = this.open_price

            #this.stddev3 = this.open_price
            #this.stddev7 = this.open_price
            #this.stddev15 = this.open_price
            #this.stddev30 = this.open_price
            #this.stddev45 = this.open_price
            #this.stddev60 = this.open_price

            
            if this.security.simFrame != 0:
                #assert(this.security.standardIndicators.state[1].simFrame+1 ==
                #this.security.simFrame,"expect to be previous day")
            
                this.datetime = this.security.standardIndicators.state[1].datetime
                this.open_price = this.security.standardIndicators.state[1].open_price_today
                this.close_price = this.security.standardIndicators.state[1].close_price
                this.returns = this.security.standardIndicators.state[1].returns_today

            
            #mavg for last x days
            #this.mavg3 = data[this.security.qsec].mavg(3)
            #this.mavg7 = data[this.security.qsec].mavg(7)
            #this.mavg15 = data[this.security.qsec].mavg(15)
            #this.mavg30 = data[this.security.qsec].mavg(30)
            #this.mavg45 = data[this.security.qsec].mavg(45)
            #this.mavg60 = data[this.security.qsec].mavg(60)

            #this.stddev3 = data[this.security.qsec].stddev(3)
            #this.stddev7 = data[this.security.qsec].stddev(7)
            #this.stddev15 = data[this.security.qsec].stddev(15)
            #this.stddev30 = data[this.security.qsec].stddev(30)
            #this.stddev45 = data[this.security.qsec].stddev(45)
            #this.stddev60 = data[this.security.qsec].stddev(60)

        def __repr__(this):
            return "c={0} mavg7={1} mavg30={2}".format(this.close_price,this.mavg7,this.mavg30)

    def initialize(this, data):
        pass
    
    def constructFrameState(this,data):
        #logger.debug("StandardTechnicalIndicators.constructFrameState")

        if this.framework.thisFrameDay == this.framework.lastFrameDay:
            #keep previous
            currentState = None
        else:
            currentState = DailyTechnicalIndicators.State(this, this.parent, data)

        return currentState
    pass



class VolatilityBiasIndicators(FrameHistory):
    ''' custom indicators used by the volatility bias strategy '''
    def initialize(this, data):
        
        pass
    
    def setWindow(this, trendPeriods, weightPeriods, triggerPeriods):
        '''set the size of the window our volatilityBias cares about
        trendPeriods #state.trend = percent the range is up, exponential weighted by timestep
        weightPeriods #state.weight = percent the range is up, linear weighted by timestep
        triggerPeriods #state.trigger = percent the range is up, linear weighted by timestep
        '''

        #internal variables
        this.trendPeriods = trendPeriods #the max history we will care about, used for determining the value of the state.trend variable
        this.weightPeriods = weightPeriods
        this.triggerPeriods = triggerPeriods
        
        this.framework.ensureMinHistory(this.trendPeriods)
        this.framework.ensureMinHistory(this.weightPeriods)
        this.framework.ensureMinHistory(this.triggerPeriods)

    '''technical indicators relating to bollinger bands'''
    class State:
        '''State recorded for each frame (minute).  number of frames history we store is determined by framework.maxHistoryFrames'''
        def __init__(this,parent, security, data):
            this.parent = parent
            this.security = security
            this.history = this.parent.state

            this.setWeight()

        def setWeight(this):
            '''computes weight by taking the price range (high-low) for each timestep, and summing them based on linear weight (most recient = more weight)'''
            #pretty confident in this port being accurate
            security = this.security
            stdState = security.standardIndicators.state

            if len(this.history)<this.parent.trendPeriods:
                this.weight = 0.0
                this.trend = 0.0
                this.trigger = 0.0
            else:
                #SET state.trend
                #trading range linear weighted by timestep
                upPortion = 0.0
                downPortion = 0.0
                span = this.parent.trendPeriods
                for i in range(0,span):
                    if stdState[i].close_price > stdState[i].open_price:
                        upPortion += ((span-i) * stdState[i].high - stdState[i].low);  
                    else:
                        downPortion +=((span-i) * stdState[i].high - stdState[i].low);  
                if (upPortion + downPortion > 0.0):
                    factor = upPortion / (upPortion + downPortion)
                    #trend = percent the range is up, exponential weighted by timestep
                    this.trend = (this.history[0].trend + factor) / 2.0
                
                #SET state.weight
                upPortion = 0.0
                downPortion = 0.0
                span = this.parent.weightPeriods
                for i in range(0,span):
                    if stdState[i].close_price > stdState[i].open_price:
                        upPortion += ((span-i) * stdState[i].high - stdState[i].low);  
                    else:
                        downPortion +=((span-i) * stdState[i].high - stdState[i].low);  
                if (upPortion + downPortion > 0.0):
                    factor = upPortion / (upPortion + downPortion)
                    #weight = percent the range is up, linear weighted by timestep
                    this.weight = factor

                #SET state.trigger
                upPortion = 0.0
                downPortion = 0.0
                span = this.parent.triggerPeriods
                for i in range(0,span):
                    if stdState[i].close_price > stdState[i].open_price:
                        upPortion += ((span-i) * stdState[i].high - stdState[i].low);  
                    else:
                        downPortion +=((span-i) * stdState[i].high - stdState[i].low);  
                if (upPortion + downPortion > 0.0):
                    factor = upPortion / (upPortion + downPortion)
                    #trigger = percent the range is up, linear weighted by timestep
                    this.trigger = factor

            return this.weight
        def __repr__(this):
            return "{0} @ {1} VOLBIAS weight={2:.2f} \t trend={3:.2f} trigger={4:.2f}".format(this.security.symbol, this.datetime, this.weight, this.trend, this.trigger)
            


    
    def constructFrameState(this,data):
        #logger.debug("VolatilityBiasIndicators.constructFrameState")
        currentState = VolatilityBiasIndicators.State(this, this.parent, data)
        return currentState    

class VolatilityBiasStrategy():
    def __init__(this, framework, data):
        this.framework = framework


        pass

    def initialize(this,data):
        
        this.trendPeriods = 53
        this.weightPeriods = 33
        this.triggerPeriods = 4

        #this.universe = this.framework._getOrCreateSecurities([
        #    sid(12915) # MDY SPDR S&P MIDCAP 400 ETF TRUST
        #    ,sid(19654) # XLB Materials Select Sector SPDR 
        #    ,sid(19655) # XLE Energy Select Sector SPDR
        #    ,sid(19656) # XLF Financial Select Sector SPDR 
        #    ,sid(19657)# XLI Industrial Select Sector SPDR
        #    ,sid(19658)#XLK  Industrial Select Sector SPDR
        #    ,sid(19659) # XLP  Consumer Staples Select Sector SPDR
        #    ,sid(19660)# XLU Utilities Select Sector SPDR
        #    ,sid(19661)# XLV Utilities Select Sector SPDR
        #    ,sid(19662) # XLY Consumer Discretionary Select Sector SPDR
        #    ,sid(25485) # AGG ISHARES CORE U.S. AGGREGATE BONDS
        #    ],data)

        this.universe = this.framework._getOrCreateSecurities([
            sid(19920) # QQQ
            , sid(2174) # DIA
            , sid(24705) # ISHARES MSCI EMERGING MARKETS "EEM"
            , sid(22972) # ISHARES MSCI EAFE ETF "EFA"
            , sid(24744) # GUGGENHEIM S&P 500 EQUAL WEIGH "RSP",
            , sid(19654) # Materials Select Sector SPDR              "XLB"
            , sid(19655) # Energy Select Sector SPDR                 "XLE"
            , sid(19656) # Financial Select Sector SPDR              "XLF"
            , sid(19657) # Industrial Select Sector SPDR             "XLI"
            , sid(19658) # Technology Select Sector SPDR            "XLK"
            , sid(19659) # Consumer Staples Select Sector SPDR        "XLP"
            , sid(19660) # Utilities Select Sector SPDR              "XLU"
            , sid(19661) # Healthcare Select Sector SPDR            "XLV"
            , sid(19662) # Consumer Discretionary Select Sector SPDR "XLY"
            , sid(22739) # VANGUARD TOTAL STOCK MARKET ETF "VTI"
            , sid(25901) # VANGUARD SMALL-CAP VALUE ETF "VBR"
            , sid(25485) # ISHARES CORE U.S. AGGREGATE BONDS "AGG"
     
            ,  sid(2)     #   Alcoa "AA"
            , sid(679)   #   Amex "AXP"
            ,  sid(698)   #   BOEING CO   "BA"
            , sid(700)   #   BANK OF AMERICA CORP   "BAC"
            , sid(734)   #   BAXTER INTERNATIONAL INC   "BAX"
            , sid(1267)  #   CATERPILLAR INC   "CAT"
            ,sid(1900)  #   CISCO SYSTEMS INC   "CSCO"
            , sid(23112) #   CHEVRON CORPORATION   "CVX"
            ,  sid(2119)  #   DU PONT DE NEMOURS E I &CO   "DD"
            , sid(2190)  #   WALT DISNEY CO-DISNEY COMMON   "DIS"
            , sid(8347)  #   EXXON MOBIL CORPORATION          "XOM"
            ,  sid(3149)  #   GENERAL ELECTRIC CO     "GE"
            ,  sid(3496)  #   HOME DEPOT INC  "HD"
            , sid(3735)  #   HEWLETT-PACKARD CO   "HPQ"
            , sid(3766)  #   INTL BUSINESS MACHINES CORP   "IBM"
            ,sid(3951)  #   INTEL CORP   "INTC"
            , sid(4151)  #   JOHNSON AND JOHNSON   "JNJ"
            , sid(25006) #   JPMORGAN CHASE & CO COM STK   "JPM"
            ,  sid(4283)  #   COCA-COLA CO   "KO"
            , sid(4707)  #   MCDONALDS CORP   "MCD"
            , sid(4922)  #   3M COMPANY   "MMM"
            , sid(5029)  #   MERCK & CO IN C  "MRK"
            ,sid(5061)  #   MICROSOFT CORP   "MSFT"
            , sid(5923)  #   PFIZER INC   "PFE"
            ,  sid(5938)  #   PROCTER & GAMBLE CO   "PG"
            ,   sid(6653)  #   AT&T INC.COM   "T"
            , sid(24845) #   Travelers "TRV"
            , sid(7792)  #   UNITEDHEALTH GROUP INC  "UNH"
            , sid(7883)  #   UNITED TECHNOLOGIES CORP   "UTX"
            ,  sid(21839) #   VERIZON COMMUNICATIONS   "VZ"
            , sid(8229)  #   WAL-MART STORES INC  "WMT"
    ],data)

    def update(this, data):
        
        if this.framework.simFrame < this.weightPeriods:
            #ensure we have our history populated
            return

        totalWeight = 0
        entries = [] #securities we will open positions with
        exits = [] #open positions we will close

        securitiesToEnumerate = this.framework.activeSecurities.items()

        for sid,security in securitiesToEnumerate:
            enter = False
            exit = False
            if security.isActive==False:
                continue

            volBiasState = security.volIndicators.state[0]
            
            if volBiasState.weight - volBiasState.trigger >= 0.40 and volBiasState.trend > 0.50:
                enter = True
            elif security.volatilityBiasStrategyPosition._currentCapitalSharePercent > 0.0:
                if volBiasState.trigger > 0.50 and volBiasState.trigger < 0.80:
                    enter = True
                else: 
                    exit = True
            else:
                exit = True

            if enter:                
                totalWeight += volBiasState.weight
                entries.append(security)
            if exit:
                exits.append(security)
                pass
            pass
        enterCount = len(entries)
        if enterCount > 0:
            for security in entries:
                #rebalance based on weights
                security.volIndicators.state[0].weight /= totalWeight
                security.volatilityBiasStrategyPosition.targetCapitalSharePercent = security.volIndicators.state[0].weight
        for security in exits:
            security.volatilityBiasStrategyPosition.targetCapitalSharePercent = 0.0
            pass

        for sid,security in securitiesToEnumerate:
            #execute trades for this timestep
            security.volatilityBiasStrategyPosition.processOrder(data)
            
       



    
    
class ExampleFramework(FrameworkBase):
    def initialize(this, data):
        
        this.volatilityBiasStrategy = VolatilityBiasStrategy(this,data)
        this.volatilityBiasStrategy.initialize(data)
        
        #this.spy = this._getOrCreateSecurity(sid(8554), data) #SPY
        

        pass

    def initializeFirstUpdate(this, data):
        #this.ensureMinHistory(360)
        pass

    def initializeSecurity(this,security, data):
        security.standardIndicators = StandardIndicators(security,this, data)
        #security.dailyIndicators = DailyTechnicalIndicators(security,this)
        security.volIndicators = VolatilityBiasIndicators(security,this, data)
        #set our securities to use the same window sizes based on a global config
        security.volIndicators.setWindow(this.volatilityBiasStrategy.trendPeriods, this.volatilityBiasStrategy.weightPeriods, this.volatilityBiasStrategy.triggerPeriods)
        security.volatilityBiasStrategyPosition = StrategyPosition(security,"volatilityBiasStrategyPosition")
        
        
        pass

    def update(this, data):

        if this.isIntradayRunDetected:
            this.minimumDifficulty = 0.99
        else:
            this.minimumDifficulty = 0.8

        #update all security indicators
        for sid,security in this.activeSecurities.items():
            security.standardIndicators._update(data)
            #security.dailyIndicators._update(data)
            security.volIndicators._update(data)
            pass

        this.volatilityBiasStrategy.update(data)

        logger.record("tradesD100",this._totalTrades / 100.0)

        #record(port_value = this.context.portfolio.portfolio_value, pos_value
        #= this.context.portfolio.positions_value , cash =
        #this.context.portfolio.cash)

    pass





##############  CONFIGURATION BELOW
def constructFramework(context,data):
    '''factory method to return your custom framework/trading algo'''
    return ExampleFramework(context,data)
There was a runtime error.

btw, if someone is interested in using QuantShim, please keep in mind that history values are inserted in-front, which is different from how quantopian likes to show it.

@Anony, as Matt said, I bet there's some survivorship bias. It's time for bed for me, but tomorrow I'll try using the quantopian 10% universe stuff and see how that goes. fyi when I used the 9 sector ETF's my returns were not nearly as good... but again, I don't have the same returns as your implementation yet, so I might have a critical bug somewhere....

How would we go about implementing this strategy with Set_Universe? And has anyone been able to run it in minute mode?

@Nihar: It would be a bit of work to use set_universe with anony's codebase, as he'd need to either move the weight logic somewhere else, or dynamically construct his security objects.

Thankfully, the quantshim port I did will make using set_universe very easy once I get the returns to match Anony's

fyi I found the bug in my port of Anony's "DJIA frequent trade" run (I was missing a parenthesis) so now the returns roughly match. The couple-percent difference I think is due to how my framework dynamically handles rebalancing.

Next I will try running with 10% universe and then get it running in minute mode. After that, I'll integrate whatever optimizations Anony has come up with since :)

Clone Algorithm
38
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
# -*- coding: utf-8 -*-  
"""

quantshim dev scratch.  Licensed under GPL3
written by [email protected]


"""



# Import the libraries we will use here
import datetime
import pytz
import math
import numpy
import pandas
import scipy
import scipy.stats
import zipline
import functools
import collections

import sklearn
import sklearn.naive_bayes
#import sklearn.naive_bayes.BernoulliNB
import sklearn.linear_model
import sklearn.ensemble

import talib




is_offline_Zipline = False

#quantopian shims
class WorstSpreadSlippage(slippage.SlippageModel):
    '''will trade at the worst value of the order minute.  high if long, low if short. 
    additionally, supports 'VolumeShareSlippage' functionality, which further biases price/volume'''
    def __init__(this, volume_limit=.25, price_impact=0.1, ohlcWeighted=False):
        this.volume_limit = volume_limit
        this.price_impact = price_impact
        this.ohlcWeighted = ohlcWeighted
        pass
    def __processVolumeShareSlippage(self,event,order, targetPrice):
        '''coppied implementation from VolumeShareSlippage.process_order(), found here: https://github.com/quantopian/zipline/blob/4860a966b3a3102fa80d43f393155e53015cc349/zipline/finance/slippage.py
        modification:  we return the final (price,volume) tuple for our main .process_order() to use, instead of executing the order
        RETURNS: final (price,volume) tuple'''
        ########
        max_volume = self.volume_limit * event.volume

        # price impact accounts for the total volume of transactions
        # created against the current minute bar
        remaining_volume = max_volume - self.volume_for_bar
        if remaining_volume < 1:
            # we can't fill any more transactions
            return (0.0,0)
        # the current order amount will be the min of the
        # volume available in the bar or the open amount.
        cur_volume = int(min(remaining_volume, abs(order.open_amount)))

        if cur_volume < 1:
            return (0.0,0)

        # tally the current amount into our total amount ordered.
        # total amount will be used to calculate price impact
        total_volume = self.volume_for_bar + cur_volume

        volume_share = min(total_volume / event.volume,
                           self.volume_limit)

        simulated_impact = volume_share ** 2 \
            * math.copysign(self.price_impact, order.direction) \
            * targetPrice
        #return create_transaction(
        #    event,
        #    order,
        #    # In the future, we may want to change the next line
        #    # for limit pricing
        #    event.price + simulated_impact,
        #    math.copysign(cur_volume, order.direction)
        return (targetPrice + simulated_impact,int(math.copysign(cur_volume, order.direction)))

    def process_order(this,trade_bar,order):
        
        #worst spread
        if order.amount < 0:
            targetPrice = trade_bar.low
        else:
            targetPrice = trade_bar.high
        #trade at the open
        #targetPrice = trade_bar.open_price

        if this.ohlcWeighted:
            #midpoint, ohlc weighted
            targetPrice = (targetPrice + trade_bar.open_price + trade_bar.high + trade_bar.low + trade_bar.close_price) / 5
            pass


        price, volume = this.__processVolumeShareSlippage(trade_bar,order,targetPrice)
        priceSlippage = trade_bar.close_price - price   
        volumeSlippage = order.amount - volume    

        if price == 0.0 or volume == 0:
            return

        #logger.info(price)
        logger.info("ORDER_COMMITTED: {0} shares {1} @ {2} \n\t  v={8} o={4} h={5} l={6} c={7} \t (WorstSpreadSlippage: vol= -{9} price= {3:.2f})"
                    .format(volume,trade_bar.sid.symbol,price,priceSlippage, trade_bar.open_price, trade_bar.high, trade_bar.low, trade_bar.close_price, trade_bar.volume,volumeSlippage))
        
        return slippage.create_transaction(trade_bar,
                                            order,
                                            price,
                                            order.amount)

class TradeAtTheOpenSlippageModel_Simple(slippage.SlippageModel):
    def __init__(self, fractionOfOpenCloseRange):
        self.fractionOfOpenCloseRange = fractionOfOpenCloseRange

    def process_order(self, trade_bar, order):
        openPrice = trade_bar.open_price
        closePrice = trade_bar.price
        ocRange = closePrice - openPrice
        ocRange = ocRange * self.fractionOfOpenCloseRange
        targetExecutionPrice = openPrice + ocRange
            
        # Create the transaction using the new price we've calculated.
        return slippage.create_transaction(
            trade_bar,
            order,
            targetExecutionPrice,
            order.amount
        )
        
class TradeAtTheOpenSlippage(slippage.SlippageModel):
    '''will trade at the open, good for daily use, kind of not good otherwise.'''
    def __init__(this, volume_limit=.25, price_impact=0.1):
        this.volume_limit = volume_limit
        this.price_impact = price_impact
        pass
    def __processVolumeShareSlippage(self,event,order, targetPrice):
        '''coppied implementation from VolumeShareSlippage.process_order(), found here: https://github.com/quantopian/zipline/blob/4860a966b3a3102fa80d43f393155e53015cc349/zipline/finance/slippage.py
        modification:  we return the final (price,volume) tuple for our main .process_order() to use, instead of executing the order
        RETURNS: final (price,volume) tuple'''
        ########
        max_volume = self.volume_limit * event.volume

        # price impact accounts for the total volume of transactions
        # created against the current minute bar
        remaining_volume = max_volume - self.volume_for_bar
        if remaining_volume < 1:
            # we can't fill any more transactions
            return (0.0,0)
        # the current order amount will be the min of the
        # volume available in the bar or the open amount.
        cur_volume = int(min(remaining_volume, abs(order.open_amount)))

        if cur_volume < 1:
            return (0.0,0)

        # tally the current amount into our total amount ordered.
        # total amount will be used to calculate price impact
        total_volume = self.volume_for_bar + cur_volume

        volume_share = min(total_volume / event.volume,
                           self.volume_limit)

        simulated_impact = volume_share ** 2 \
            * math.copysign(self.price_impact, order.direction) \
            * targetPrice
        #return create_transaction(
        #    event,
        #    order,
        #    # In the future, we may want to change the next line
        #    # for limit pricing
        #    event.price + simulated_impact,
        #    math.copysign(cur_volume, order.direction)
        return (targetPrice + simulated_impact,int(math.copysign(cur_volume, order.direction)))

    def process_order(this,trade_bar,order):
        
        
        #if order.amount < 0:
        #    targetPrice = trade_bar.low
        #else:
        #    targetPrice = trade_bar.high
        targetPrice = trade_bar.open_price

        price, volume = this.__processVolumeShareSlippage(trade_bar,order,targetPrice)
        priceSlippage = trade_bar.close_price - price   
        volumeSlippage = order.amount - volume    

        if price == 0.0 or volume == 0:
            return

        #logger.info(price)
        logger.info("ORDER_COMMITTED: {0} shares {1} @ {2} \n\t  v={8} o={4} h={5} l={6} c={7} \t (TradeAtTheOpenSlippage: vol= -{9} price= {3:.2f})"
                    .format(volume,trade_bar.sid.symbol,price,priceSlippage, trade_bar.open_price, trade_bar.high, trade_bar.low, trade_bar.close_price, trade_bar.volume,volumeSlippage))
        
        return slippage.create_transaction(trade_bar,
                                            order,
                                            price,
                                            order.amount)

    
class CustomSlippage(slippage.SlippageModel):
    ''' allows customizing slippage if desired, though mostly used for logging your order details to the console'''
    def __init__(this, volume_limit=.25, price_impact=0.1, ohlcWeighted=False):
        this.volume_limit = volume_limit
        this.price_impact = price_impact
        this.ohlcWeighted = ohlcWeighted
        pass
    def __processVolumeShareSlippage(self,event,order, targetPrice):
        '''coppied implementation from VolumeShareSlippage.process_order(), found here: https://github.com/quantopian/zipline/blob/4860a966b3a3102fa80d43f393155e53015cc349/zipline/finance/slippage.py
        modification:  we return the final (price,volume) tuple for our main .process_order() to use, instead of executing the order
        RETURNS: final (price,volume) tuple'''
        ########
        max_volume = self.volume_limit * event.volume

        # price impact accounts for the total volume of transactions
        # created against the current minute bar
        remaining_volume = max_volume - self.volume_for_bar
        if remaining_volume < 1:
            # we can't fill any more transactions
            return (0.0,0)
        # the current order amount will be the min of the
        # volume available in the bar or the open amount.
        cur_volume = int(min(remaining_volume, abs(order.open_amount)))

        if cur_volume < 1:
            return (0.0,0)

        # tally the current amount into our total amount ordered.
        # total amount will be used to calculate price impact
        total_volume = self.volume_for_bar + cur_volume

        volume_share = min(total_volume / event.volume,
                           self.volume_limit)

        simulated_impact = volume_share ** 2 * math.copysign(self.price_impact, order.direction) * targetPrice
        #return create_transaction(
        #    event,
        #    order,
        #    # In the future, we may want to change the next line
        #    # for limit pricing
        #    event.price + simulated_impact,
        #    math.copysign(cur_volume, order.direction)
        return (targetPrice + simulated_impact,int(math.copysign(cur_volume, order.direction)))

    def process_order(this,trade_bar,order):
        
        ####worst spread
        #if order.amount < 0:
        #    targetPrice = trade_bar.low
        #else:
        #    targetPrice = trade_bar.high
        ####trade at the open
        #targetPrice = trade_bar.open_price
        ####trade at the close
        targetPrice = trade_bar.close_price

        if this.ohlcWeighted:
            #midpoint, ohlc weighted
            targetPrice = (targetPrice + trade_bar.open_price + trade_bar.high + trade_bar.low + trade_bar.close_price) / 5
            pass


        price, volume = this.__processVolumeShareSlippage(trade_bar,order,targetPrice)
        priceSlippage = trade_bar.close_price - price   
        volumeSlippage = order.amount - volume    

        if price == 0.0 or volume == 0:
            return
        
        
        #construct our pnl once this transaction is comitted (logged below)
        pnl = _g.context.portfolio.pnl + (price * order.amount) - (trade_bar.close_price * order.amount)

        #logger.info(price)
        logger.info("ORDER_COMMITTED: {0} shares {1} @ {2} \n\t  v={8} o={4} h={5} l={6} c={7} \t (Slippage: vol= -{9} price= {3:.2f})\n\tpnl={10}"
                    .format(volume,trade_bar.sid.symbol,price,priceSlippage, trade_bar.open_price, trade_bar.high, trade_bar.low, trade_bar.close_price, trade_bar.volume,volumeSlippage, pnl))
        
        return slippage.create_transaction(trade_bar,
                                            order,
                                            price,
                                            order.amount)

class Logger():
    '''shim for exposing the same logging definitions to visualstudio intelisence'''
    def __init__(this, logErrors=True, logInfos=True, logWarns=True, logDebugs=True):        
        this.__logErrors = logErrors
        this.__logInfos = logInfos
        this.__logWarns = logWarns
        this.__logDebugs = logDebugs
        this.__recordHistory = {}
        this.__lastKnownDay = None
        pass    

    def error(this, message): 
        if not this.__logErrors: return  
        log.error(this.__wrapMessage(message))
        pass
    def info(this, message):
        if not this.__logInfos: return  
        log.info(this.__wrapMessage(message))
        pass
    def warn(this, message):   
        if not this.__logWarns: return  
        log.warn(this.__wrapMessage(message))
        pass
    def debug(this, message):  
        if not this.__logDebugs: return  
        log.debug(this.__wrapMessage(message))
        pass

    def __wrapMessage(this,message):
        this.__trySpamDailyLogs() 
        timestamp = _g.context.framework._getDatetime()
        
        #return str(timestamp) + message
        time = timestamp.strftime("%H:%M")
        
        #if timestamp.second!=0:
        #    time += ":{0}".format(timestamp.second)

        return str(time) + ": " + str(message)
        pass

    def debugAccumulateDaily(this,key,message):
        '''writes the log once a day to avoid spam.  includes timestamp automatically'''
        if not this.__logDebugs: return  
        msg = this.__wrapMessage(message)
        this.__storeToDailyLog(key,msg)

    def debugOnceDaily(this,key,message):
        if not this.__logDebugs: return  
        
        this.__storeToDailyLog(key,message)
        this.__recordHistory[key] = this.__recordHistory[key][0:1]
        this.__trySpamDailyLogs()
        pass
    def __storeToDailyLog(this,key,message):
        if not this.__recordHistory.has_key(key):
            this.__recordHistory[key] = []
        this.__recordHistory[key].append(message)

        pass

    def __trySpamDailyLogs(this):
        if _g.context.framework.thisFrameDay != this.__lastKnownDay:
            #new day, dump our previous logs
            this.__lastKnownDay = _g.context.framework.thisFrameDay   
            for key,values in this.__recordHistory.items():                         
                this.debug("[email protected]{0}=\n{1}".format(key,",".join(values)))
                values[:] = [] #clear it
        pass

    def record(this, name,value, logDaily=False):                    
        this.__trySpamDailyLogs()            
        if(logDaily == True):
            this.__storeToDailyLog(name,"%0.4f" % value)
        record(**{name:value})

    def recordNormalized(this, name,value,baseline=1,subtract=0, logDaily=False):    
        '''normalize values to a 0 to 1 range'''

        if value - subtract == 0 or baseline == 0:
            toRecord = 0
        else:
            toRecord = (value - subtract) / baseline

        this.record(name,toRecord,logDaily=logDaily)

    #def getLastRecord(this,name):
    #    '''returns the last recorded value.  only exists if doing daily
    #    outputs, and during the day.  returns None if name not found'''
    #    return this.__recordHistory.get(name)
    pass

global logger
logger = Logger() #(logDebugs=False)

class Shims():
    '''SHIM OF QUANTOPIAN INTERNAL REPRESENTATION.  here for intelisence only.  you SHOULD NOT actually instantiate these.'''
    
    class Position:
        '''
        The position object represents a current open position, and is contained inside the positions dictionary. 
        For example, if you had an open AAPL position, you'd access it using context.portfolio.positions[sid(24)]. 
        The position object has the following properties:
            amount = 0 #Integer: Whole number of shares in this position.
            cost_basis = 0.0 #Float: The volume-weighted average price paid per share in this position.
            last_sale_price = 0.0 #Float: Price at last sale of this security.
            sid = 0 #Integer: The ID of the security.
        '''
        def __init__(this):
            this.amount = 0 #Integer: Whole number of shares in this position.
            this.cost_basis = 0.0 #Float: The volume-weighted average price paid per share in this position.
            this.last_sale_price = 0.0 #Float: Price at last sale of this security.
            this.sid = 0 #Integer: The ID of the security.

    class Context():
        def __init__(this , portfolio=zipline.protocol.Portfolio()): #, tradingAlgorithm = zipline.TradingAlgorithm()):
            this.portfolio = portfolio
            #this.tradingAlgorithm = tradingAlgorithm
            pass
        pass

    


    

    class _TradingAlgorithm_QuantopianShim:
        '''shim of zipline.TradingAlgorithm for use on quantopian '''
        def __init__(this):
            #this.logger = Shims._Logger()
            #this.logger = log
            pass
        

        def order(this,sid,amount,limit_price=None, stop_price=None):
            '''
            Places an order for the specified security of the specified number of shares. Order type is inferred from the parameters used. If only sid and amount are used as parameters, the order is placed as a market order.
            Parameters
            sid: A security object.
            amount: The integer amount of shares. Positive means buy, negative means sell.
            limit_price: (optional) The price at which the limit order becomes active. If used with stop_price, the price where the limit order becomes active after stop_price is reached.
            stop_price: (optional) The price at which the order converts to a market order. If used with limit_price, the price where the order converts to a limit order.
            Returns
            An order id.
            '''
            if sid is Security:
                security = sid
            else:
                security = this.context.framework.allSecurities[sid]
            #logger.info("{0} ordering {1}".format(security.qsec,amount))
            orderId = order(security.qsec,amount,limit_price,stop_price)
            return orderId
            pass

        def order_percent(self, sid, percent, limit_price=None, stop_price=None):
            """
            Place an order in the specified security corresponding to the given
            percent of the current portfolio value.

            Note that percent must expressed as a decimal (0.50 means 50\%).
            """
            value = self.context.portfolio.portfolio_value * percent
            return self.order_value(sid, value, limit_price, stop_price)

        def order_target(self, sid, target, limit_price=None, stop_price=None):
            """
            Place an order to adjust a position to a target number of shares. If
            the position doesn't already exist, this is equivalent to placing a new
            order. If the position does exist, this is equivalent to placing an
            order for the difference between the target number of shares and the
            current number of shares.
            """
            if sid in self.context.portfolio.positions:
                current_position = self.context.portfolio.positions[sid].amount
                req_shares = target - current_position
                return self.order(sid, req_shares, limit_price, stop_price)
            else:
                return self.order(sid, target, limit_price, stop_price)

        def order_target_value(self, sid, target, limit_price=None,
                               stop_price=None):
            """
            Place an order to adjust a position to a target value. If
            the position doesn't already exist, this is equivalent to placing a new
            order. If the position does exist, this is equivalent to placing an
            order for the difference between the target value and the
            current value.
            """
            if sid in self.context.portfolio.positions:
                current_position = self.context.portfolio.positions[sid].amount
                current_price = self.context.portfolio.positions[sid].last_sale_price
                current_value = current_position * current_price
                req_value = target - current_value
                return self.order_value(sid, req_value, limit_price, stop_price)
            else:
                return self.order_value(sid, target, limit_price, stop_price)

        def order_target_percent(self, sid, target, limit_price=None,
                                 stop_price=None):
            """
            Place an order to adjust a position to a target percent of the
            current portfolio value. If the position doesn't already exist, this is
            equivalent to placing a new order. If the position does exist, this is
            equivalent to placing an order for the difference between the target
            percent and the current percent.

            Note that target must expressed as a decimal (0.50 means 50\%).
            """
            if sid in self.context.portfolio.positions:
                current_position = self.context.portfolio.positions[sid].amount
                current_price = self.context.portfolio.positions[sid].last_sale_price
                current_value = current_position * current_price
            else:
                current_value = 0
            target_value = self.context.portfolio.portfolio_value * target

            req_value = target_value - current_value
            return self.order_value(sid, req_value, limit_price, stop_price)

        pass

    #class _TradingAlgorithm_ZiplineShim(zipline.TradingAlgorithm):
    #    '''auto-generates a context to use'''
    #    def initialize(this):
    #        #delay initialize until start of first handle-data, so our
    #        #portfolio object is available
    #        #this.__isInitialized = False;
    #        this.context = Shims.Context()
    #        this.context.tradingAlgorithm = this            
    #        #this.context.portfolio = this.portfolio
    #        pass

    #    def handle_data(this,data):      
    #        this.context.portfolio = this.portfolio
    #        #if not this.__isInitialized:
    #        #    this.__isInitialized=True
    #        #    this.context.portfolio=this.portfolio
                
    #        this.context.framework._update(data)
    #        pass
    #    pass

class FrameHistory:
    def __init__(this,parent,framework, data):
        this.parent = parent
        this.framework = framework
        this.state = []
        this.isActive = this.parent.isActive
        #this.maxHistoryFrames = this.framework.maxHistoryFrames
        #assert(this.framework.simFrame == this.parent.simFrame, "parent frame
        #does not match")
        
        this.initialize(data)
    
    def initialize(this, data):
        '''overridable'''
        logger.error("FrameHistory.initialize() invoked.  You should override this method.")
        pass

    def constructFrameState(this,data):
        '''override and return the frame state, this will be prepended to history
        if you return NONE, the frame state (history) is not modified.'''   
        logger.error("FrameHistory.constructFrameState() invoked.  You should override this method.")             
        pass

    def _update(this,data):
        this.isActive = this.parent.isActive
        if not this.isActive:
            return

        

        currentState = this.constructFrameState(data)
        if(currentState != None):
            currentState.datetime = this.framework._getDatetime()
            currentState.simFrame = this.framework.simFrame

            this.state.insert(0,currentState)
            del this.state[this.framework.maxHistoryFrames:]

class StrategyPosition:
    '''allows two or more stratgies to controll their own positions (orders) for securities they care about, 
    without interfering with the orders of other strategies.

    To use:   each strategy should set security.myStrategyPositon.targetCapitalSharePercent, which is a percentage of your entire portfolio's value
    then execute the order (and/or rebalance) by invoking security.myStrategyPosition.processOrder()
    '''

    def __init__(this, security, strategyName):            
        this._security = security
        this._strategyName = strategyName
        this._lastOrderId = 0
        this._lastStopOrderId = 0
        this._currentCapitalSharePercent = 0.0
        this._currentShares = 0
        #for the last trade roundtrip, the aproximate returns.  set every time our percent changes to zero
        this._lastRoundtripReturns = 0.0
        #this is editable
        this.targetCapitalSharePercent = 0.0
        #price when we decided to order, not actually the fulfillment price
        this.__lastOrderPrice = 0.0
        this.__currentPeakGains = 0.0
        this.__currentPeakGainsDecay = 0.0
        this._currentReturns = 0.0 #returns of current open position. 
        this._totalTrades = 0 #total trades we execute via this strategyPosition.  note that due to partial fills, this may be less than actual trades

    def processOrder(this, data, rebalanceThreshholdPercent=0.05, maxLosses=None, maxGainsAdditionalDrawdown=None, maxGainsDecay=0.01): #, OBSOLETE_stopLimitPercent=0.0, OBSOLETE_momentumStopLimit = True, OBSOLETE_decayMomentum = 0.001):
        ''' set rebalanceThreshholdPercent to zero (0.0) to cause the position to readjust even if the targetPercentage doesn't change.   this is useful for reinvesting divideds / etc
        but is set to 0.05 (5 percent) so we don't spam orders 
        
        maxLosses:  close if our open position suffers a loss of this percent or more
        maxGainsAdditionalDrawdown : close if our open position's gains suffer a decrease of this+maxLosses or more.
        maxGainsDecay : over time this will reduce the acceptable gains drawdown (specified by maxGainsAdditionalDrawdown) so that on long-running gains we don't incur such a large drawdown before closing.
        '''
        #if momentumStopLimit == True (the default) we will stopLimitPercent based on the peak gains, not based on the original purchase price (this is generally a good ideas as it will maximize your gains)
        #decayMomentum : = if == 0.01 and using momentumStopLimit==True, we will decay the position's survival chances by 1% per tick until it's finally closed.
        
        if this._currentCapitalSharePercent == 0.0 and this.targetCapitalSharePercent == 0.0:
            #no work to do
            return 0



        currentPrice = data[this._security.qsec].close_price
        
        if this._currentCapitalSharePercent == this.targetCapitalSharePercent and this._currentCapitalSharePercent != 0.0:
            #update current returns
            this._currentReturns = (currentPrice - this.__lastOrderPrice) / this.__lastOrderPrice * math.copysign(1.0,this._currentCapitalSharePercent)
        else:
            #target is different so reset our returns as we are about to change our order
            this._currentReturns = 0.0


        if this._currentCapitalSharePercent == this.targetCapitalSharePercent and maxGainsAdditionalDrawdown != None:
            ##handle maxGains stoplimits
            gainsPercent = this._currentReturns - this.__currentPeakGainsDecay
            #if gainsPercent < -maxLosses:
            #    #loosing, so close out
            #    logger.debug("loosing, so close out.  gainsPercent={0}, maxLosses={1}".format(gainsPercent, maxLosses))
            #    this.targetCapitalSharePercent = 0.0 
            #else:

            if this._currentReturns > this.__currentPeakGains:
                this.__currentPeakGains = this._currentReturns
                this.__currentPeakGainsDecay = 0.0 #reset decay 
            else:
                #need to see if our gain exceed our stoplimitGains threshhold
                gainsFloorThreshhold = this.__currentPeakGains * maxGainsAdditionalDrawdown
                if gainsPercent < gainsFloorThreshhold:
                    lossesFromPeak = this.__currentPeakGains - gainsPercent
                    if maxLosses != None and lossesFromPeak < maxLosses:
                        #we are not yet exceeding maxLosses (from our peak) so don't close out yet
                        logger.debug("we are not yet exceeding maxLosses (from our peak) so don't close out yet.  \t {0} @ {1}, gains={2}".format(this._security.symbol,currentPrice,this._currentReturns))
                        pass
                    else:
                        #loosing from our peak, so close out
                        logger.debug("loosing from our peak, so close out.  gainsPercent={0:.4f}, \t gainsFloorThreshhold={1:.4f}, \t  lossesFromPeak={2:.4f}, \t  maxLosses={3:.4f}  \t this._currentReturns={4:.4f}".format(gainsPercent, gainsFloorThreshhold, lossesFromPeak, maxLosses,this._currentReturns))
                        this.targetCapitalSharePercent = 0.0 

                this.__currentPeakGainsDecay += (this.__currentPeakGains * maxGainsDecay)
        else:
            this.__currentPeakGains = 0.0
            this.__currentPeakGainsDecay = 0.0

        if this._currentCapitalSharePercent == this.targetCapitalSharePercent and this._currentCapitalSharePercent != 0.0:
            #handle maxlosses stoplimit
            if maxLosses != None and this._currentReturns < -maxLosses:
                logger.debug("maxlosses stoplimit.  this._currentReturns={0}, maxLosses={1}".format(this._currentReturns, maxLosses))
                this.targetCapitalSharePercent = 0.0


           

        if this.targetCapitalSharePercent == 0.0 and this._currentCapitalSharePercent != 0.0:
            #record our expected PnL
            this._lastRoundtripReturns = this._currentReturns

        this._currentCapitalSharePercent = this.targetCapitalSharePercent
        
        
           
        #determine value of percent
        targetSharesValue = this._security.framework.context.portfolio.portfolio_value * this._currentCapitalSharePercent
        targetSharesTotal = int(math.copysign(math.floor(abs(targetSharesValue / currentPrice)),targetSharesValue))
        
        targetSharesDelta = targetSharesTotal - this._currentShares

        if targetSharesTotal != 0:
            if abs(targetSharesDelta / (targetSharesTotal * 1.0)) < rebalanceThreshholdPercent:
                #logger.debug("{0} ORDER SKIPPED! {1} (change to small) : {2} + {3} => {4} shares".format(this.strategyName,this.security.symbol, this.currentShares, targetSharesDelta, targetSharesTotal))          
                #our position change was too small so we skip rebalancing
                return

        #do actual order
        if(abs(targetSharesDelta) >= 1): #can not perform an order on less than 1 share
            ####cancel previous open order, if any  #doesn't really work, as even when canceling, some shares may be filled so you'll be left in an uncomplete state
            ###lastOrder = get_order(this.lastOrderId)
            ###unfilled = lastOrder.amount - l
            ###cancel_order(this.lastOrderId)
            logger.info("{0} order {1} : {2} + {3} => {4} shares  \t \t decisionPrice={5} ".format(this._strategyName,this._security.symbol, this._currentShares, targetSharesDelta, targetSharesTotal,currentPrice))          
            this._lastOrderId = this._security.framework.tradingAlgorithm.order(this._security.sid,targetSharesDelta,None,None)
            this._currentShares = targetSharesTotal
            this.__lastOrderPrice = currentPrice
            this._totalTrades += 1
            this._security.framework._totalTrades += 1
            
            return this._lastOrderId
        else:
            return 0

class Security:
    isDebug = False


    class QSecurity:
        '''
        Quantopian internal security object
        If you have a reference to a security object, there are several properties that might be useful:
            sid = 0 #Integer: The id of this security.
            symbol = "" #String: The ticker symbol of this security.
            security_name = "" #String: The full name of this security.
            security_start_date = datetime.datetime() #Datetime: The date when this security first started trading.
            security_end_date = datetime.datetime() #Datetime: The date when this security stopped trading (= yesterday for securities that are trading normally, because that's the last day for which we have historical price data).
        '''
        def __init__(this):
            this.sid = 0 #Integer: The id of this security.
            this.symbol = "" #String: The ticker symbol of this security.
            this.security_name = "" #String: The full name of this security.
            this.security_start_date = datetime.datetime(1990,1,1) #Datetime: The date when this security first started trading.
            this.security_end_date = datetime.datetime(1990,1,1) #Datetime: The date when this security stopped trading (= yesterday for securities that are trading normally, because that's the last day for which we have historical price data).
    
    

    def __init__(this,sid, framework):
        this.sid = sid  
        this.isActive = False
        this.framework = framework
        this.security_start_date = datetime.datetime.utcfromtimestamp(0)
        this.security_end_date = datetime.datetime.utcfromtimestamp(0)
        this.simFrame = -1
        this.security_start_price = 0.0
        this.security_end_price = 0.0
        #this.daily_open_price = [0.0]
        #this.daily_close_price = [0.0]
        this.symbol = "??? Not yet active so symbol not known"
        
        
    def getCurrentPosition(this):
        if this.simFrame == -1:
            return Shims.Position()
        return this.framework.context.portfolio.positions[this.qsec]

    def update(this,qsec, data):
        '''qsec is only given when it's in scope, and it can actually change each timestep 
        what it does:
        - construct new state for this frame
        - update qsec to most recent (if any)
        '''
        #update our tickcounter, mostly for debug
        this.simFrame = this.framework.simFrame
        #assert(this.simFrame >= 0,"security.update() frame not set")

        
        
        #update qsec to most recent (if any) 67
        this.qsec = qsec
        if qsec:
            this.isActive = True
            this.symbol = qsec.symbol
            #assert(qsec.sid == this.sid,"security.update() sids do not match")
            
            if this.security_start_price == 0.0:
                this.security_start_price = data[this.sid].close_price
            this.security_end_price = data[this.sid].close_price

            this.security_start_date = qsec.security_start_date
            this.security_end_date = qsec.security_end_date
        else:
            this.isActive = False

        #try:
        #    this.daily_close_price =
        #    this.framework.daily_close_price[this.qsec]
        #    this.daily_open_price = this.framework.daily_open_price[this.qsec]
        #except:
        #    this.daily_close_price = []
        #    this.daily_open_price = []

        #if len(this.daily_close_price) == 0 or len(this.daily_open_price) ==
        #0:
        #    this.isActive = False
class FrameworkBase():
    def __init__(this, context, data, maxHistoryFrames=60): #5 days of history
        this.maxHistoryFrames = maxHistoryFrames
        this.__isFirstTimestepRun = False
        this.context = context
        this.tradingAlgorithm = Shims._TradingAlgorithm_QuantopianShim() #prepopulate to allow intelisence
        this.tradingAlgorithm = context.tradingAlgorithm
        this.simFrame = -1 #the current timestep of the simulation
        this.framesToday = -1 #number of frames executed today
        
        this.allSecurities = {} #dictionary of all securities, including those not targeted
        
        this.activeSecurities = {}

        #stub for intelisence propigation
        this.allSecurities["1"]=Security(0,this)
        this.allSecurities.clear()


        this.thisFrameDay = 0
        this.lastFrameDay = 0

        this._totalTrades = 0 #total trades we execute via all strategyPositions.  note that due to partial fills, this may be less than actual trades

        this.isIntradayRunDetected = False #if we are running in intraday, this will be set to true on frame 2.  the 2nd bar will be in the same day as the first bar.  no better way to detect unfortunately.

        #for storing quantopian history
        #this.daily_close_price = pandas.DataFrame()
        #this.daily_open_price = pandas.DataFrame()
        
        this._initialize(data)

        pass
    def ensureMinHistory(this, minFrames):
        '''increases the history frames if the current is less than your required min.  
        this is a good way to set your history, as too much history will slow down your sim, and can crash it due to out-of-memory'''

        if this.maxHistoryFrames < minFrames:
            this.maxHistoryFrames = minFrames      
    
    def _initialize(this, data):
        '''starts initialiation of the framework
        do not override this, or any other method starting with an underscore.
        methods without an underscore prefix can and should be overridden.'''
        #do init here
        this.initialize(data)        
        pass

    def initialize(this, data):
        '''override this to do your init'''
        logger.error("You should override FrameworkBase.initialize()")
        pass


    def initializeFirstUpdate(this,data):
        '''override this.  called the first timestep, before update.  
        provides access to the 'data' object which normal .initialize() does not'''
        logger.error("You should override FrameworkBase.initializeFirstUpdate()")
        pass

    def _update(this,data):

        '''invoked by the tradingAlgorithm shim every update.  internally we will call abstract_update_timestep_handle_data()
        DO NOT OVERRIDE THIS OR ANY METHODS STARTING WITH AN UNDERSCORE
        override methods without underscores.
        '''
        
        #frame updates
        #this.data = data

        this.simFrame+=1        
        
        this.lastFrameDay = this.thisFrameDay
        this.thisFrameDay = this._getDatetime().day

        
        #supdating our history once per day
        if(this.thisFrameDay != this.lastFrameDay):
            #only update this once per day, hopefully improving performance...
            #this.daily_close_price = history(bar_count=180, frequency='1d',
            #field='close_price')
            #this.daily_open_price = history(bar_count=180, frequency='1d',
            #field='open_price')
            this.framesToday = 0
        else:
            this.framesToday += 1
            this.isIntradayRunDetected = True

        this.__updateSecurities(data)
        

        if not this.__isFirstTimestepRun:
            this.__isFirstTimestepRun = True
            this.initializeFirstUpdate(data)

        this.update(data)
        pass

    def update(this,data):
        '''override and update your usercode here'''
        logger.error("You should override FrameworkBase.update()")
        pass

    def __updateSecurities(this,data):
        '''get all qsecs from data, then update the targetedSecurities accordingly'''
        #logger.debug("FrameworkBase.__updateSecurities() start.
        #allSecLength={0}".format(len(this.allSecurities)))
        #convert our data into a dictionary
        currentQSecs = {}
        newQSecs = {}
        for qsec in data:            
            #if online, qsec is a securities object
            sid = qsec.sid      
            
            #logger.debug("FrameworkBase.__updateSecurities() first loop, found
            #{0}, sid={1}.  exists={2}".format(qsec,
            #sid,this.allSecurities.has_key(sid) ))

            currentQSecs[sid] = qsec
            #determine new securities found in data
            if not this.allSecurities.has_key(sid):
                logger.debug("FrameworkBase.__updateSecurities() new security detected.  will construct our security object for it: {0}".format(qsec))
                newQSecs[sid] = qsec


        #construct new Security objects for our newQSecs
        for sid, qsec in newQSecs.items():            
            #assert(not
            #this.allSecurities.has_key(sid),"frameworkBase.updateSecurities
            #key does not exist")
            #logger.debug("FrameworkBase.__updateSecurities() new security
            #found {0}".format(qsec))
            security = this._getOrCreateSecurity(qsec, data)
            this.allSecurities[security.sid] = security

        newQSecs.clear()

        #update all security objects, giving a null qsec if one doesn't exist
        #in our data dictionary
        for sid, security1 in this.allSecurities.items():
            qsec = currentQSecs.get(sid)
            security1.update(qsec, data)

        ## determine active securities set.
        this.activeSecurities.clear()
        for sid,security2 in this.allSecurities.items():
            if not security2.isActive:
                #logger.debug("FrameworkBase.__updateSecurities() NOT ACTIVE
                #{0}".format(security.qsec))
                continue
            #logger.debug("FrameworkBase.__updateSecurities() ACTIVE
            #{0}".format(security.qsec))
            this.activeSecurities[sid] = security2
            pass

        pass

    def initializeSecurity(this,security, data):
        '''override to do custom init logic on each security. 
        if you wish to use your own security, return it (it will replace the existing)'''
        logger.error("You should override FrameworkBase.initializeSecurity()")
        pass       
             
    def _getOrCreateSecurities(this,qsecArray, data):
        '''pass in an array of quantopian sid/sec tuples  (ex:  [(24,sid(24)),(3113,sid(3113))]) 
        and returns an array of unique security objects wrapping them.   duplicate sids are ignored'''

        securities = {}

        for qsec in qsecArray:            
            security = this._getOrCreateSecurity(qsec, data)
            securities[security.sid] = security
            pass

        return securities.values()

    def _getOrCreateSecurity(this, qsec, data):
        '''pass in a quantopian sec (ex:  sid(24)) and returns our security object wrapping it
        if the security object
        '''
        
        sid = qsec.sid
        if this.allSecurities.has_key(sid):
            return this.allSecurities[sid]

        #does not exist, have to create
        newSecurity = Security(sid,this)
        #new, so do our framework's custom init logic on this security
        maybeNewSec = this.initializeSecurity(newSecurity, data)
        if maybeNewSec is not None:
            #framework replaced newSec with a different sec
            newSecurity = maybeNewSec
                
        this.allSecurities[sid] = newSecurity
        
        return newSecurity
        pass


    def _getDatetime(this):
        '''returns current market time, using US/Eastern timezone'''
        return pandas.Timestamp(pandas.Timestamp(get_datetime()).tz_convert('US/Eastern'))
#entrypoints

def handle_data(context=Shims.Context(),data=pandas.DataFrame()):   
    '''update method run every timestep on quantopian'''
    
    #try: 
    if context.firstFrame:
        #'''init on our first frame'''
        context.firstFrame = False
        context.tradingAlgorithm = Shims._TradingAlgorithm_QuantopianShim()
        context.tradingAlgorithm.context = context
        context.framework = constructFramework(context,data)
        
    
    context.framework._update(data)
    #except Exception,e:
    #    print "Caught:",e

    pass

class Global():
    pass
global _g
_g = Global()




def initialize(context=Shims.Context()):
    '''initialize method used when running on quantopian'''
    context.firstFrame = True 
    
    _g.context = context
    #context.spy = sid(8554) #SPY
    ########## SET UNIVERSE
    #if you need set universe, do it here (note that doing this slows the algo
    #considerably)
    #set_universe(universe.DollarVolumeUniverse(floor_percentile=90.0,ceiling_percentile=100.0))
    #context.universe = [#sid(698)         #BA
    #    #sid(8554) #SPY
    #    #sid(27098) #ISE

    #    ####################### 9 sector etfs
    #    sid(19662) # XLY Consumer Discrectionary SPDR Fund
    #    ,sid(19656) # XLF Financial SPDR Fund
    #    ,sid(19658) # XLK Technology SPDR Fund
    #    ,sid(19655) # XLE Energy SPDR Fund
    #    ,sid(19661) # XLV Health Care SPRD Fund
    #    ,sid(19657) # XLI Industrial SPDR Fund
    #    ,sid(19659) # XLP Consumer Staples SPDR Fund
    #    ,sid(19654) # XLB Materials SPDR Fund
    #    ,sid(19660) # XLU Utilities SPRD Fund
    #    ]

    #aprox 200 SPY constituents from fetcher
    #fetch_csv(
    #   "https://googledrive.com/host/0BwZ2bMDOKaeDYWYzYzgxNDYtNmQyYi00ZDk5LWE3ZTYtODQ0ZDAzNTBkY2M4/trading/SP500-20131001.csv",
    #    pre_func=preview,
    #    date_column='date',
    #    universe_func=(my_universe))
    #aprox 90 hardcoded SPY constituents
    #my_static_universe(context) 

    ########## COMMISSION
    #use top to decrease uncertainty when testing algorithms
    #set_commission(commission.PerShare(cost=0.0))
    #set_commission(commission.PerShare(cost=0.005, min_trade_cost=1.00)) #IB
    #fixed commission model
    #set_commission(commission.PerShare(cost=0.013, min_trade_cost=1.3)) #more
    #agressive...
    
    ########## SLIPPAGE
    #use top to decrease uncertainty when testing algorithms
    #set_slippage(slippage.FixedSlippage(spread=0.00))
    #set_slippage(slippage.FixedSlippage(spread=0.01))
    #set_slippage(WorstSpreadSlippage())
    #set_slippage(CustomSlippage(1.0,0.0))

    ############# Anony values
    set_commission(commission.PerTrade(cost=1.0))
    set_slippage(TradeAtTheOpenSlippageModel_Simple(0.1))

##############  USERCODE BELOW.  EDIT BELOW THIS LINE
##############  USERCODE BELOW.  EDIT BELOW THIS LINE
##############  USERCODE BELOW.  EDIT BELOW THIS LINE


class BBTechnicalIndicators(FrameHistory):
    '''technical indicators relating to bollinger bands'''
    class State:
        '''State recorded for each frame (minute).  number of frames history we store is determined by framework.maxHistoryFrames'''
        def __init__(this,parent, security, data):
            this.parent = parent
            this.security = security
            this.history = this.parent.state

            bb = this.parent.bbands_data[this.security.sid]
            #will be NaN if not enough period
            this.upperLimit = bb[0]
            this.line = bb[1]
            this.lowerLimit = bb[2]
            #see https://www.tradingview.com/stock-charts-support/index.php/Bollinger_Bands_%25B_(%25B)
            this.percentB = (this.security.standardIndicators.state[0].close_price - this.lowerLimit) / (this.upperLimit - this.lowerLimit)
            #see https://www.tradingview.com/stock-charts-support/index.php/Bollinger_Bands_Width_(BBW)
            this.bbw = (this.upperLimit - this.lowerLimit) / this.line
            #track slope of %B, to determine if rising (positive) or falling (negative)
            if len(this.history) > 0:
                this.percentBSlope = (this.percentB - this.history[0].percentB)
                this.bbwSlope = (this.bbw - this.history[0].bbw)
                this.percentBPercentile = scipy.stats.percentileofscore([state.percentB for state in this.history],this.percentB,"mean") / 100.0
                this.bbwPercentile = scipy.stats.percentileofscore([state.bbw for state in this.history],this.bbw,"mean") / 100.0 
                this.lineSlope = (this.line - this.history[0].line)
            else:
                this.percentBSlope = 0.0
                this.bbwSlope = 0.0
                this.percentBPercentile = 0.5
                this.bbwPercentile = 0.5
                this.lineSlope = 0.0

            #track momentum
            if this.percentB > 0.8:
                if len(this.history) > 0:
                    this.upperMomentumTicks = this.history[0].upperMomentumTicks + 1
                else:
                    this.upperMomentumTicks = 1
            else:
                this.upperMomentumTicks = 0            
            if this.percentB < 0.2:
                if len(this.history) > 0:
                    this.lowerMomentumTicks = this.history[0].lowerMomentumTicks + 1
                else:
                    this.lowerMomentumTicks = 1
            else:
                this.lowerMomentumTicks = 0





            #logger.debug(" bb for {0} is {1}".format(this.security.symbol, bb));
            
            #logger.recordNormalized("upperLimit",this.upperLimit,this.security.security_start_price)
            #logger.recordNormalized("line",this.line,this.security.security_start_price)
            #logger.recordNormalized("lowerLimit",this.lowerLimit,this.security.security_start_price)

            #logger.record("upperBar",1.0)
            #logger.record("lowerBar",0.0)
            #logger.record("upperApproach",0.8)
            #logger.record("lowerApproach",0.2)
            #logger.record("percentB",this.percentB);

        def __repr__(this):
            return "{0} @ {1} BBANDS l={2:.2f} \t upper={3:.2f} lower={4:.2f}".format(this.security.symbol, this.datetime, this.line, this.upperLimit, this.lowerLimit)


    def initialize(this, data):
        this.bbands = ta.BBANDS(timeperiod=20,nbdevup=2, nbdevdn=2,matype=0) #output: Dictionary of sid to tuples, where each tuple is three floats: (upperLimit, line, lowerLimit).
        this.bbands_data = this.bbands(data)
        pass
    
    def constructFrameState(this,data):
        #logger.debug("BBTechnicalIndicators.constructFrameState")
        currentState = BBTechnicalIndicators.State(this, this.parent, data)
        return currentState

class StandardIndicators(FrameHistory):
    '''common technical indicators that we plan to use for any/all strategies
    feel free to extend this, or use as a reference for constructing specialized technical indicators'''
    class State:
        '''State recorded for each frame (minute).  number of frames history we store is determined by framework.maxHistoryFrames'''
        def __init__(this,parent, security, data):
            this.parent = parent
            this.security = security
            this.history = this.parent.state

            #preset for proper intelisence
            this.datetime = datetime.datetime.now()
            this.open_price = 0.0
            this.close_price = 0.0
            this.high = 0.0
            this.low = 0.0
            this.volume = 0

            #this.mavg3 = 0.0
            #this.mavg7 = 0.0
            #this.mavg15 = 0.0
            #this.mavg30 = 0.0
            #this.mavg45 = 0.0
            #this.mavg60 = 0.0

            #this.stddev3 = 0.0
            #this.stddev7 = 0.0
            #this.stddev15 = 0.0
            #this.stddev30 = 0.0
            #this.stddev45 = 0.0
            #this.stddev60 = 0.0

            this.datetime = data[this.security.qsec].datetime
            this.open_price = data[this.security.qsec].open_price
            this.close_price = data[this.security.qsec].close_price
            this.high = data[this.security.qsec].high
            this.low = data[this.security.qsec].low
            this.volume = data[this.security.qsec].volume
                        
            
            #mavg for last x minutes
            #this.mavg3 = numpy.mean([state.close_price for state in
            #this.history[0:3]])
            #this.mavg7 = numpy.mean([state.close_price for state in
            #this.history[0:7]])
            #this.mavg15 = numpy.mean([state.close_price for state in
            #this.history[0:15]])
            #this.mavg30 = numpy.mean([state.close_price for state in
            #this.history[0:30]])
            #this.mavg45 = numpy.mean([state.close_price for state in
            #this.history[0:45]])
            #this.mavg60 = numpy.mean([state.close_price for state in
            #this.history[0:60]])

            #this.stddev3 = numpy.std([state.close_price for state in
            #this.history[0:3]])
            #this.stddev7 = numpy.std([state.close_price for state in
            #this.history[0:7]])
            #this.stddev15 = numpy.std([state.close_price for state in
            #this.history[0:15]])
            #this.stddev30 = numpy.std([state.close_price for state in
            #this.history[0:30]])
            #this.stddev45 = numpy.std([state.close_price for state in
            #this.history[0:45]])
            #this.stddev60 = numpy.std([state.close_price for state in
            #this.history[0:60]])

            if len(this.history) < 1:                
                this.returns = 0.0
                this.returns_median_abs = 0.0
            else:
                #always returns compared to last timestep
                this.returns = (this.close_price - this.history[0].close_price) / this.history[0].close_price
                if len(this.history) == 1:
                    this.returns_median_abs = abs(this.returns)
                else:
                    this.returns_median_abs = numpy.median([abs(state.returns) for state in this.history])

            try:                
                #when in intraday mode, stores cumulative returns through the day
                this.returns_today = data[this.security.qsec].returns()
            except:
                this.framework.logger.error("{0} unable to obtain returns()  setting returns to zero  open={1}.  close = {2}".format(this.parent.qsec, this.open_price, this.close_price))
                this.returns_today = 0.0
            pass

            #daily accumulations
            if this.security.framework.thisFrameDay != this.security.framework.lastFrameDay or len(this.history) < 1:
                this.open_price_today = this.open_price
                #if len(this.history) < 1:
                    
                #    this.open_price_yesterday = this.open_price_today
                #    this.close_price_yesterday = this.close_price
                #    this.returns_yesterday = this.returns_today
                ##new day, so record our start of day values
                #else:
                #    this.open_price_yesterday =
                #    this.history[0].open_price_today
                #    this.close_price_yesterday = this.history[0].close_price
                #    this.returns_yesterday = this.history[0].returns_today
            else:
                this.open_price_today = this.history[0].open_price_today
                #this.open_price_yesterday =
                #this.history[0].open_price_yesterday
                #this.close_price_yesterday =
                #this.history[0].close_price_yesterday
                #this.returns_yesterday = this.history[0].returns_yesterday

        def __repr__(this):
            return "{0} @ {1} c={0}".format(this.security.symbol, this.datetime, this.close_price)

    def initialize(this, data):
        pass
    
    def constructFrameState(this,data):
        #logger.debug("StandardTechnicalIndicators.constructFrameState")
        currentState = StandardIndicators.State(this, this.parent, data)
        return currentState


class DailyTechnicalIndicators(FrameHistory):
    '''standard technical indicators for the entire day
    for daily history.   the .state[] history does not include the current day, only previous days'''
    class State:
        '''State recorded for each previous day.  number of frames history we store is determined by framework.maxHistoryFrames'''
        def __init__(this,parent, security, data):
            this.parent = parent
            this.security = security
            this.history = this.parent.state



            #preset for proper intelisence
            this.datetime = datetime.datetime.now()


            #setting these to default to yesterday's value so that for the
            #first day of our simulation we get reasonable values
            this.open_price = data[this.security.qsec].mavg(1)
            this.close_price = this.open_price
            #this.high = 0.0
            #this.low = 0.0
            #this.volume = 0

            #this.mavg3 = this.open_price
            #this.mavg7 = this.open_price
            #this.mavg15 = this.open_price
            #this.mavg30 = this.open_price
            #this.mavg45 = this.open_price
            #this.mavg60 = this.open_price

            #this.stddev3 = this.open_price
            #this.stddev7 = this.open_price
            #this.stddev15 = this.open_price
            #this.stddev30 = this.open_price
            #this.stddev45 = this.open_price
            #this.stddev60 = this.open_price

            
            if this.security.simFrame != 0:
                #assert(this.security.standardIndicators.state[1].simFrame+1 ==
                #this.security.simFrame,"expect to be previous day")
            
                this.datetime = this.security.standardIndicators.state[1].datetime
                this.open_price = this.security.standardIndicators.state[1].open_price_today
                this.close_price = this.security.standardIndicators.state[1].close_price
                this.returns = this.security.standardIndicators.state[1].returns_today

            
            #mavg for last x days
            #this.mavg3 = data[this.security.qsec].mavg(3)
            #this.mavg7 = data[this.security.qsec].mavg(7)
            #this.mavg15 = data[this.security.qsec].mavg(15)
            #this.mavg30 = data[this.security.qsec].mavg(30)
            #this.mavg45 = data[this.security.qsec].mavg(45)
            #this.mavg60 = data[this.security.qsec].mavg(60)

            #this.stddev3 = data[this.security.qsec].stddev(3)
            #this.stddev7 = data[this.security.qsec].stddev(7)
            #this.stddev15 = data[this.security.qsec].stddev(15)
            #this.stddev30 = data[this.security.qsec].stddev(30)
            #this.stddev45 = data[this.security.qsec].stddev(45)
            #this.stddev60 = data[this.security.qsec].stddev(60)

        def __repr__(this):
            return "c={0} mavg7={1} mavg30={2}".format(this.close_price,this.mavg7,this.mavg30)

    def initialize(this, data):
        pass
    
    def constructFrameState(this,data):
        #logger.debug("StandardTechnicalIndicators.constructFrameState")

        if this.framework.thisFrameDay == this.framework.lastFrameDay:
            #keep previous
            currentState = None
        else:
            currentState = DailyTechnicalIndicators.State(this, this.parent, data)

        return currentState
    pass



class VolatilityBiasIndicators(FrameHistory):
    ''' custom indicators used by the volatility bias strategy '''
    def initialize(this, data):
        
        pass
    
    def setWindow(this, trendPeriods, weightPeriods, triggerPeriods):
        '''set the size of the window our volatilityBias cares about
        trendPeriods #state.trend = percent the range is up, exponential weighted by timestep
        weightPeriods #state.weight = percent the range is up, linear weighted by timestep
        triggerPeriods #state.trigger = percent the range is up, linear weighted by timestep
        '''

        #internal variables
        this.trendPeriods = trendPeriods #the max history we will care about, used for determining the value of the state.trend variable
        this.weightPeriods = weightPeriods
        this.triggerPeriods = triggerPeriods
        
        this.framework.ensureMinHistory(this.trendPeriods)
        this.framework.ensureMinHistory(this.weightPeriods)
        this.framework.ensureMinHistory(this.triggerPeriods)

    '''technical indicators relating to bollinger bands'''
    class State:
        '''State recorded for each frame (minute).  number of frames history we store is determined by framework.maxHistoryFrames'''
        def __init__(this,parent, security, data):
            this.parent = parent
            this.security = security
            this.history = this.parent.state

            

            this.setWeight()

        def setWeight(this):
            '''computes weight by taking the price range (high-low) for each timestep, and summing them based on linear weight (most recient = more weight)'''
            #pretty confident in this port being accurate
            security = this.security
            stdState = security.standardIndicators.state
            stdStateLen = len(stdState)

            #set default values
            if len(this.history)== 0:
                this.weight = 0.0
                this.trend = 0.0
                this.trigger = 0.0
                return
            else:
                #set initial value equal to previous values
                this.weight = this.history[0].weight
                this.trend = this.history[0].trend
                this.trigger = this.history[0].trigger

            #SET state.trend
            #trading range linear weighted by timestep
            upPortion = 0.0
            downPortion = 0.0
            span = this.parent.trendPeriods if stdStateLen > this.parent.trendPeriods else stdStateLen
            for i in range(0,span):
                if stdState[i].close_price > stdState[i].open_price:
                    upPortion += ((span-i) * (stdState[i].high - stdState[i].low));  
                else:
                    downPortion +=((span-i) * (stdState[i].high - stdState[i].low));  
            if (upPortion + downPortion > 0.0):
                factor = upPortion / (upPortion + downPortion)
                #trend = percent the range is up, exponential weighted by timestep
                this.trend = (this.history[0].trend + factor) / 2.0
            #logger.info("sec={0} \t span={1} upP={2} dwnP={3} fac={4} trend={5}".format(this.security.symbol,span,upPortion,downPortion, factor, this.trend))
            #SET state.weight
            if stdStateLen > this.parent.weightPeriods:                
                upPortion = 0.0
                downPortion = 0.0
                span = this.parent.weightPeriods
                for i in range(0,span):
                    if stdState[i].close_price > stdState[i].open_price:
                        upPortion += ((span-i) * (stdState[i].high - stdState[i].low));  
                    else:
                        downPortion +=((span-i) * (stdState[i].high - stdState[i].low));  
                if (upPortion + downPortion > 0.0):
                    factor = upPortion / (upPortion + downPortion)
                    #weight = percent the range is up, linear weighted by timestep
                    this.weight = factor

            #SET state.trigger
            if stdStateLen > this.parent.triggerPeriods:                
                upPortion = 0.0
                downPortion = 0.0
                span = this.parent.triggerPeriods
                for i in range(0,span):
                    if stdState[i].close_price > stdState[i].open_price:
                        upPortion += ((span-i) * (stdState[i].high - stdState[i].low));  
                    else:
                        downPortion +=((span-i) * (stdState[i].high - stdState[i].low));  
                if (upPortion + downPortion > 0.0):
                    factor = upPortion / (upPortion + downPortion)
                    #trigger = percent the range is up, linear weighted by timestep
                    this.trigger = factor

            return this.weight

        def __repr__(this):
            return "{0} @ {1} VOLBIAS weight={2:.2f} \t trend={3:.2f} trigger={4:.2f}".format(this.security.symbol, this.datetime, this.weight, this.trend, this.trigger)
            


    
    def constructFrameState(this,data):
        #logger.debug("VolatilityBiasIndicators.constructFrameState")
        currentState = VolatilityBiasIndicators.State(this, this.parent, data)
        return currentState    

class VolatilityBiasStrategy():
    def __init__(this, framework, data):
        this.framework = framework


        pass

    def initialize(this,data):
        
        this.trendPeriods = 53
        this.weightPeriods = 33
        this.triggerPeriods = 4

        #this.universe = this.framework._getOrCreateSecurities([
        #    sid(12915) # MDY SPDR S&P MIDCAP 400 ETF TRUST
        #    ,sid(19654) # XLB Materials Select Sector SPDR 
        #    ,sid(19655) # XLE Energy Select Sector SPDR
        #    ,sid(19656) # XLF Financial Select Sector SPDR 
        #    ,sid(19657)# XLI Industrial Select Sector SPDR
        #    ,sid(19658)#XLK  Industrial Select Sector SPDR
        #    ,sid(19659) # XLP  Consumer Staples Select Sector SPDR
        #    ,sid(19660)# XLU Utilities Select Sector SPDR
        #    ,sid(19661)# XLV Utilities Select Sector SPDR
        #    ,sid(19662) # XLY Consumer Discretionary Select Sector SPDR
        #    ,sid(25485) # AGG ISHARES CORE U.S. AGGREGATE BONDS
        #    ],data)

        this.universe = this.framework._getOrCreateSecurities([
            sid(19920) # QQQ
            , sid(2174) # DIA
            , sid(24705) # ISHARES MSCI EMERGING MARKETS "EEM"
            , sid(22972) # ISHARES MSCI EAFE ETF "EFA"
            , sid(24744) # GUGGENHEIM S&P 500 EQUAL WEIGH "RSP",
            , sid(19654) # Materials Select Sector SPDR              "XLB"
            , sid(19655) # Energy Select Sector SPDR                 "XLE"
            , sid(19656) # Financial Select Sector SPDR              "XLF"
            , sid(19657) # Industrial Select Sector SPDR             "XLI"
            , sid(19658) # Technology Select Sector SPDR            "XLK"
            , sid(19659) # Consumer Staples Select Sector SPDR        "XLP"
            , sid(19660) # Utilities Select Sector SPDR              "XLU"
            , sid(19661) # Healthcare Select Sector SPDR            "XLV"
            , sid(19662) # Consumer Discretionary Select Sector SPDR "XLY"
            , sid(22739) # VANGUARD TOTAL STOCK MARKET ETF "VTI"
            , sid(25901) # VANGUARD SMALL-CAP VALUE ETF "VBR"
            , sid(25485) # ISHARES CORE U.S. AGGREGATE BONDS "AGG"
     
            ,  sid(2)     #   Alcoa "AA"
            , sid(679)   #   Amex "AXP"
            ,  sid(698)   #   BOEING CO   "BA"
            , sid(700)   #   BANK OF AMERICA CORP   "BAC"
            , sid(734)   #   BAXTER INTERNATIONAL INC   "BAX"
            , sid(1267)  #   CATERPILLAR INC   "CAT"
            ,sid(1900)  #   CISCO SYSTEMS INC   "CSCO"
            , sid(23112) #   CHEVRON CORPORATION   "CVX"
            ,  sid(2119)  #   DU PONT DE NEMOURS E I &CO   "DD"
            , sid(2190)  #   WALT DISNEY CO-DISNEY COMMON   "DIS"
            , sid(8347)  #   EXXON MOBIL CORPORATION          "XOM"
            ,  sid(3149)  #   GENERAL ELECTRIC CO     "GE"
            ,  sid(3496)  #   HOME DEPOT INC  "HD"
            , sid(3735)  #   HEWLETT-PACKARD CO   "HPQ"
            , sid(3766)  #   INTL BUSINESS MACHINES CORP   "IBM"
            ,sid(3951)  #   INTEL CORP   "INTC"
            , sid(4151)  #   JOHNSON AND JOHNSON   "JNJ"
            , sid(25006) #   JPMORGAN CHASE & CO COM STK   "JPM"
            ,  sid(4283)  #   COCA-COLA CO   "KO"
            , sid(4707)  #   MCDONALDS CORP   "MCD"
            , sid(4922)  #   3M COMPANY   "MMM"
            , sid(5029)  #   MERCK & CO IN C  "MRK"
            ,sid(5061)  #   MICROSOFT CORP   "MSFT"
            , sid(5923)  #   PFIZER INC   "PFE"
            ,  sid(5938)  #   PROCTER & GAMBLE CO   "PG"
            ,   sid(6653)  #   AT&T INC.COM   "T"
            , sid(24845) #   Travelers "TRV"
            , sid(7792)  #   UNITEDHEALTH GROUP INC  "UNH"
            , sid(7883)  #   UNITED TECHNOLOGIES CORP   "UTX"
            ,  sid(21839) #   VERIZON COMMUNICATIONS   "VZ"
            , sid(8229)  #   WAL-MART STORES INC  "WMT"
    ],data)

    def update(this, data):
        
        if this.framework.simFrame < (this.weightPeriods -1):
            #ensure we have our history populated
            return

        totalWeight = 0
        entries = [] #securities we will open positions with
        exits = [] #open positions we will close

        securitiesToEnumerate = this.framework.activeSecurities.items()

        for sid,security in securitiesToEnumerate:
            enter = False
            exit = False
            if security.isActive==False:
                continue

            volBiasState = security.volBiasIndicators.state[0]
            
            if volBiasState.weight - volBiasState.trigger >= 0.40 and volBiasState.trend > 0.50:
                enter = True
            elif security.volatilityBiasStrategyPosition._currentCapitalSharePercent > 0.0:
                if volBiasState.trigger > 0.50 and volBiasState.trigger < 0.80:
                    enter = True
                else: 
                    exit = True
            else:
                exit = True

            if enter:                
                totalWeight += volBiasState.weight
                entries.append(security)
            if exit:
                exits.append(security)
                pass
            pass
        enterCount = len(entries)
        if enterCount > 0:
            for security in entries:
                #rebalance based on weights
                security.volBiasIndicators.state[0].weight /= totalWeight
                security.volatilityBiasStrategyPosition.targetCapitalSharePercent = security.volBiasIndicators.state[0].weight
        for security in exits:
            security.volatilityBiasStrategyPosition.targetCapitalSharePercent = 0.0
            pass

        for sid,security in securitiesToEnumerate:
            #execute trades for this timestep
            security.volatilityBiasStrategyPosition.processOrder(data)
            
        logger.record("Weight",this.universe[0].volBiasIndicators.state[0].weight)
        logger.record("Trigger",this.universe[0].volBiasIndicators.state[0].trigger)
        logger.record("Trend",this.universe[0].volBiasIndicators.state[0].trend)
            
       



    
    
class ExampleFramework(FrameworkBase):
    def initialize(this, data):
        
        this.volatilityBiasStrategy = VolatilityBiasStrategy(this,data)
        this.volatilityBiasStrategy.initialize(data)
        
        #this.spy = this._getOrCreateSecurity(sid(8554), data) #SPY
        

        pass

    def initializeFirstUpdate(this, data):
        #this.ensureMinHistory(360)
        pass

    def initializeSecurity(this,security, data):
        security.standardIndicators = StandardIndicators(security,this, data)
        #security.dailyIndicators = DailyTechnicalIndicators(security,this)
        security.volBiasIndicators = VolatilityBiasIndicators(security,this, data)
        #set our securities to use the same window sizes based on a global config
        security.volBiasIndicators.setWindow(this.volatilityBiasStrategy.trendPeriods, this.volatilityBiasStrategy.weightPeriods, this.volatilityBiasStrategy.triggerPeriods)
        security.volatilityBiasStrategyPosition = StrategyPosition(security,"volatilityBiasStrategyPosition")
        
        
        pass

    def update(this, data):
        #update all security indicators
        for sid,security in this.activeSecurities.items():
            security.standardIndicators._update(data)
            #security.dailyIndicators._update(data)
            security.volBiasIndicators._update(data)
            pass

        this.volatilityBiasStrategy.update(data)

        #logger.record("tradesD100",this._totalTrades / 100.0)

    pass





##############  CONFIGURATION BELOW
def constructFramework(context,data):
    '''factory method to return your custom framework/trading algo'''
    return ExampleFramework(context,data)

There was a runtime error.

@Anony: re your inverted weights, in my testing with various portfolios this only has a slight (if any) impact on returns. for example your initial "DJIA" portfolio has almost the exact returns. I presume this is due to your weights hovering in the 0.5 range to begin with.

I've attached a run using the top 10% universe. This guarantees a bias free portfolio, and the results are significantly worse, but still promising due to the potential of decreasing the excessive trades

However, I don't think I'll be converting to minute mode just yet. the 10% universe took more than 2 hours to run, so I'll play with the other interesting improvement ideas first. Minute mode will take 10x or so longer to test so I think we can do that a bit later :)

Clone Algorithm
38
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
# -*- coding: utf-8 -*-  
"""

quantshim dev scratch.  Licensed under GPL3
written by [email protected]


"""



# Import the libraries we will use here
import datetime
import pytz
import math
import numpy
import pandas
import scipy
import scipy.stats
import zipline
import functools
import collections

import sklearn
import sklearn.naive_bayes
#import sklearn.naive_bayes.BernoulliNB
import sklearn.linear_model
import sklearn.ensemble

import talib




is_offline_Zipline = False

#quantopian shims
class WorstSpreadSlippage(slippage.SlippageModel):
    '''will trade at the worst value of the order minute.  high if long, low if short. 
    additionally, supports 'VolumeShareSlippage' functionality, which further biases price/volume'''
    def __init__(this, volume_limit=.25, price_impact=0.1, ohlcWeighted=False):
        this.volume_limit = volume_limit
        this.price_impact = price_impact
        this.ohlcWeighted = ohlcWeighted
        pass
    def __processVolumeShareSlippage(self,event,order, targetPrice):
        '''coppied implementation from VolumeShareSlippage.process_order(), found here: https://github.com/quantopian/zipline/blob/4860a966b3a3102fa80d43f393155e53015cc349/zipline/finance/slippage.py
        modification:  we return the final (price,volume) tuple for our main .process_order() to use, instead of executing the order
        RETURNS: final (price,volume) tuple'''
        ########
        max_volume = self.volume_limit * event.volume

        # price impact accounts for the total volume of transactions
        # created against the current minute bar
        remaining_volume = max_volume - self.volume_for_bar
        if remaining_volume < 1:
            # we can't fill any more transactions
            return (0.0,0)
        # the current order amount will be the min of the
        # volume available in the bar or the open amount.
        cur_volume = int(min(remaining_volume, abs(order.open_amount)))

        if cur_volume < 1:
            return (0.0,0)

        # tally the current amount into our total amount ordered.
        # total amount will be used to calculate price impact
        total_volume = self.volume_for_bar + cur_volume

        volume_share = min(total_volume / event.volume,
                           self.volume_limit)

        simulated_impact = volume_share ** 2 \
            * math.copysign(self.price_impact, order.direction) \
            * targetPrice
        #return create_transaction(
        #    event,
        #    order,
        #    # In the future, we may want to change the next line
        #    # for limit pricing
        #    event.price + simulated_impact,
        #    math.copysign(cur_volume, order.direction)
        return (targetPrice + simulated_impact,int(math.copysign(cur_volume, order.direction)))

    def process_order(this,trade_bar,order):
        
        #worst spread
        if order.amount < 0:
            targetPrice = trade_bar.low
        else:
            targetPrice = trade_bar.high
        #trade at the open
        #targetPrice = trade_bar.open_price

        if this.ohlcWeighted:
            #midpoint, ohlc weighted
            targetPrice = (targetPrice + trade_bar.open_price + trade_bar.high + trade_bar.low + trade_bar.close_price) / 5
            pass


        price, volume = this.__processVolumeShareSlippage(trade_bar,order,targetPrice)
        priceSlippage = trade_bar.close_price - price   
        volumeSlippage = order.amount - volume    

        if price == 0.0 or volume == 0:
            return

        #logger.info(price)
        logger.info("ORDER_COMMITTED: {0} shares {1} @ {2} \n\t  v={8} o={4} h={5} l={6} c={7} \t (WorstSpreadSlippage: vol= -{9} price= {3:.2f})"
                    .format(volume,trade_bar.sid.symbol,price,priceSlippage, trade_bar.open_price, trade_bar.high, trade_bar.low, trade_bar.close_price, trade_bar.volume,volumeSlippage))
        
        return slippage.create_transaction(trade_bar,
                                            order,
                                            price,
                                            order.amount)

class TradeAtTheOpenSlippageModel_Simple(slippage.SlippageModel):
    def __init__(self, fractionOfOpenCloseRange):
        self.fractionOfOpenCloseRange = fractionOfOpenCloseRange

    def process_order(self, trade_bar, order):
        openPrice = trade_bar.open_price
        closePrice = trade_bar.price
        ocRange = closePrice - openPrice
        ocRange = ocRange * self.fractionOfOpenCloseRange
        targetExecutionPrice = openPrice + ocRange
            
        # Create the transaction using the new price we've calculated.
        return slippage.create_transaction(
            trade_bar,
            order,
            targetExecutionPrice,
            order.amount
        )
        
class TradeAtTheOpenSlippage(slippage.SlippageModel):
    '''will trade at the open, good for daily use, kind of not good otherwise.'''
    def __init__(this, volume_limit=.25, price_impact=0.1):
        this.volume_limit = volume_limit
        this.price_impact = price_impact
        pass
    def __processVolumeShareSlippage(self,event,order, targetPrice):
        '''coppied implementation from VolumeShareSlippage.process_order(), found here: https://github.com/quantopian/zipline/blob/4860a966b3a3102fa80d43f393155e53015cc349/zipline/finance/slippage.py
        modification:  we return the final (price,volume) tuple for our main .process_order() to use, instead of executing the order
        RETURNS: final (price,volume) tuple'''
        ########
        max_volume = self.volume_limit * event.volume

        # price impact accounts for the total volume of transactions
        # created against the current minute bar
        remaining_volume = max_volume - self.volume_for_bar
        if remaining_volume < 1:
            # we can't fill any more transactions
            return (0.0,0)
        # the current order amount will be the min of the
        # volume available in the bar or the open amount.
        cur_volume = int(min(remaining_volume, abs(order.open_amount)))

        if cur_volume < 1:
            return (0.0,0)

        # tally the current amount into our total amount ordered.
        # total amount will be used to calculate price impact
        total_volume = self.volume_for_bar + cur_volume

        volume_share = min(total_volume / event.volume,
                           self.volume_limit)

        simulated_impact = volume_share ** 2 \
            * math.copysign(self.price_impact, order.direction) \
            * targetPrice
        #return create_transaction(
        #    event,
        #    order,
        #    # In the future, we may want to change the next line
        #    # for limit pricing
        #    event.price + simulated_impact,
        #    math.copysign(cur_volume, order.direction)
        return (targetPrice + simulated_impact,int(math.copysign(cur_volume, order.direction)))

    def process_order(this,trade_bar,order):
        
        
        #if order.amount < 0:
        #    targetPrice = trade_bar.low
        #else:
        #    targetPrice = trade_bar.high
        targetPrice = trade_bar.open_price

        price, volume = this.__processVolumeShareSlippage(trade_bar,order,targetPrice)
        priceSlippage = trade_bar.close_price - price   
        volumeSlippage = order.amount - volume    

        if price == 0.0 or volume == 0:
            return

        #logger.info(price)
        logger.info("ORDER_COMMITTED: {0} shares {1} @ {2} \n\t  v={8} o={4} h={5} l={6} c={7} \t (TradeAtTheOpenSlippage: vol= -{9} price= {3:.2f})"
                    .format(volume,trade_bar.sid.symbol,price,priceSlippage, trade_bar.open_price, trade_bar.high, trade_bar.low, trade_bar.close_price, trade_bar.volume,volumeSlippage))
        
        return slippage.create_transaction(trade_bar,
                                            order,
                                            price,
                                            order.amount)

    
class CustomSlippage(slippage.SlippageModel):
    ''' allows customizing slippage if desired, though mostly used for logging your order details to the console'''
    def __init__(this, volume_limit=.25, price_impact=0.1, ohlcWeighted=False):
        this.volume_limit = volume_limit
        this.price_impact = price_impact
        this.ohlcWeighted = ohlcWeighted
        pass
    def __processVolumeShareSlippage(self,event,order, targetPrice):
        '''coppied implementation from VolumeShareSlippage.process_order(), found here: https://github.com/quantopian/zipline/blob/4860a966b3a3102fa80d43f393155e53015cc349/zipline/finance/slippage.py
        modification:  we return the final (price,volume) tuple for our main .process_order() to use, instead of executing the order
        RETURNS: final (price,volume) tuple'''
        ########
        max_volume = self.volume_limit * event.volume

        # price impact accounts for the total volume of transactions
        # created against the current minute bar
        remaining_volume = max_volume - self.volume_for_bar
        if remaining_volume < 1:
            # we can't fill any more transactions
            return (0.0,0)
        # the current order amount will be the min of the
        # volume available in the bar or the open amount.
        cur_volume = int(min(remaining_volume, abs(order.open_amount)))

        if cur_volume < 1:
            return (0.0,0)

        # tally the current amount into our total amount ordered.
        # total amount will be used to calculate price impact
        total_volume = self.volume_for_bar + cur_volume

        volume_share = min(total_volume / event.volume,
                           self.volume_limit)

        simulated_impact = volume_share ** 2 * math.copysign(self.price_impact, order.direction) * targetPrice
        #return create_transaction(
        #    event,
        #    order,
        #    # In the future, we may want to change the next line
        #    # for limit pricing
        #    event.price + simulated_impact,
        #    math.copysign(cur_volume, order.direction)
        return (targetPrice + simulated_impact,int(math.copysign(cur_volume, order.direction)))

    def process_order(this,trade_bar,order):
        
        ####worst spread
        #if order.amount < 0:
        #    targetPrice = trade_bar.low
        #else:
        #    targetPrice = trade_bar.high
        ####trade at the open
        #targetPrice = trade_bar.open_price
        ####trade at the close
        targetPrice = trade_bar.close_price

        if this.ohlcWeighted:
            #midpoint, ohlc weighted
            targetPrice = (targetPrice + trade_bar.open_price + trade_bar.high + trade_bar.low + trade_bar.close_price) / 5
            pass


        price, volume = this.__processVolumeShareSlippage(trade_bar,order,targetPrice)
        priceSlippage = trade_bar.close_price - price   
        volumeSlippage = order.amount - volume    

        if price == 0.0 or volume == 0:
            return
        
        
        #construct our pnl once this transaction is comitted (logged below)
        pnl = _g.context.portfolio.pnl + (price * order.amount) - (trade_bar.close_price * order.amount)

        #logger.info(price)
        logger.info("ORDER_COMMITTED: {0} shares {1} @ {2} \n\t  v={8} o={4} h={5} l={6} c={7} \t (Slippage: vol= -{9} price= {3:.2f})\n\tpnl={10}"
                    .format(volume,trade_bar.sid.symbol,price,priceSlippage, trade_bar.open_price, trade_bar.high, trade_bar.low, trade_bar.close_price, trade_bar.volume,volumeSlippage, pnl))
        
        return slippage.create_transaction(trade_bar,
                                            order,
                                            price,
                                            order.amount)

class Logger():
    '''shim for exposing the same logging definitions to visualstudio intelisence'''
    def __init__(this, logErrors=True, logInfos=True, logWarns=True, logDebugs=True):        
        this.__logErrors = logErrors
        this.__logInfos = logInfos
        this.__logWarns = logWarns
        this.__logDebugs = logDebugs
        this.__recordHistory = {}
        this.__lastKnownDay = None
        pass    

    def error(this, message): 
        if not this.__logErrors: return  
        log.error(this.__wrapMessage(message))
        pass
    def info(this, message):
        if not this.__logInfos: return  
        log.info(this.__wrapMessage(message))
        pass
    def warn(this, message):   
        if not this.__logWarns: return  
        log.warn(this.__wrapMessage(message))
        pass
    def debug(this, message):  
        if not this.__logDebugs: return  
        log.debug(this.__wrapMessage(message))
        pass

    def __wrapMessage(this,message):
        this.__trySpamDailyLogs() 
        timestamp = _g.context.framework._getDatetime()
        
        #return str(timestamp) + message
        time = timestamp.strftime("%H:%M")
        
        #if timestamp.second!=0:
        #    time += ":{0}".format(timestamp.second)

        return str(time) + ": " + str(message)
        pass

    def debugAccumulateDaily(this,key,message):
        '''writes the log once a day to avoid spam.  includes timestamp automatically'''
        if not this.__logDebugs: return  
        msg = this.__wrapMessage(message)
        this.__storeToDailyLog(key,msg)

    def debugOnceDaily(this,key,message):
        if not this.__logDebugs: return  
        
        this.__storeToDailyLog(key,message)
        this.__recordHistory[key] = this.__recordHistory[key][0:1]
        this.__trySpamDailyLogs()
        pass
    def __storeToDailyLog(this,key,message):
        if not this.__recordHistory.has_key(key):
            this.__recordHistory[key] = []
        this.__recordHistory[key].append(message)

        pass

    def __trySpamDailyLogs(this):
        if _g.context.framework.thisFrameDay != this.__lastKnownDay:
            #new day, dump our previous logs
            this.__lastKnownDay = _g.context.framework.thisFrameDay   
            for key,values in this.__recordHistory.items():                         
                this.debug("[email protected]{0}=\n{1}".format(key,",".join(values)))
                values[:] = [] #clear it
        pass

    def record(this, name,value, logDaily=False):                    
        this.__trySpamDailyLogs()            
        if(logDaily == True):
            this.__storeToDailyLog(name,"%0.4f" % value)
        record(**{name:value})

    def recordNormalized(this, name,value,baseline=1,subtract=0, logDaily=False):    
        '''normalize values to a 0 to 1 range'''

        if value - subtract == 0 or baseline == 0:
            toRecord = 0
        else:
            toRecord = (value - subtract) / baseline

        this.record(name,toRecord,logDaily=logDaily)

    #def getLastRecord(this,name):
    #    '''returns the last recorded value.  only exists if doing daily
    #    outputs, and during the day.  returns None if name not found'''
    #    return this.__recordHistory.get(name)
    pass

global logger
logger = Logger() #(logDebugs=False)

class Shims():
    '''SHIM OF QUANTOPIAN INTERNAL REPRESENTATION.  here for intelisence only.  you SHOULD NOT actually instantiate these.'''
    
    class Position:
        '''
        The position object represents a current open position, and is contained inside the positions dictionary. 
        For example, if you had an open AAPL position, you'd access it using context.portfolio.positions[sid(24)]. 
        The position object has the following properties:
            amount = 0 #Integer: Whole number of shares in this position.
            cost_basis = 0.0 #Float: The volume-weighted average price paid per share in this position.
            last_sale_price = 0.0 #Float: Price at last sale of this security.
            sid = 0 #Integer: The ID of the security.
        '''
        def __init__(this):
            this.amount = 0 #Integer: Whole number of shares in this position.
            this.cost_basis = 0.0 #Float: The volume-weighted average price paid per share in this position.
            this.last_sale_price = 0.0 #Float: Price at last sale of this security.
            this.sid = 0 #Integer: The ID of the security.

    class Context():
        def __init__(this , portfolio=zipline.protocol.Portfolio()): #, tradingAlgorithm = zipline.TradingAlgorithm()):
            this.portfolio = portfolio
            #this.tradingAlgorithm = tradingAlgorithm
            pass
        pass

    


    

    class _TradingAlgorithm_QuantopianShim:
        '''shim of zipline.TradingAlgorithm for use on quantopian '''
        def __init__(this):
            #this.logger = Shims._Logger()
            #this.logger = log
            pass
        

        def order(this,sid,amount,limit_price=None, stop_price=None):
            '''
            Places an order for the specified security of the specified number of shares. Order type is inferred from the parameters used. If only sid and amount are used as parameters, the order is placed as a market order.
            Parameters
            sid: A security object.
            amount: The integer amount of shares. Positive means buy, negative means sell.
            limit_price: (optional) The price at which the limit order becomes active. If used with stop_price, the price where the limit order becomes active after stop_price is reached.
            stop_price: (optional) The price at which the order converts to a market order. If used with limit_price, the price where the order converts to a limit order.
            Returns
            An order id.
            '''
            if sid is Security:
                security = sid
            else:
                security = this.context.framework.allSecurities[sid]
            #logger.info("{0} ordering {1}".format(security.qsec,amount))
            orderId = order(security.qsec,amount,limit_price,stop_price)
            return orderId
            pass

        def order_percent(self, sid, percent, limit_price=None, stop_price=None):
            """
            Place an order in the specified security corresponding to the given
            percent of the current portfolio value.

            Note that percent must expressed as a decimal (0.50 means 50\%).
            """
            value = self.context.portfolio.portfolio_value * percent
            return self.order_value(sid, value, limit_price, stop_price)

        def order_target(self, sid, target, limit_price=None, stop_price=None):
            """
            Place an order to adjust a position to a target number of shares. If
            the position doesn't already exist, this is equivalent to placing a new
            order. If the position does exist, this is equivalent to placing an
            order for the difference between the target number of shares and the
            current number of shares.
            """
            if sid in self.context.portfolio.positions:
                current_position = self.context.portfolio.positions[sid].amount
                req_shares = target - current_position
                return self.order(sid, req_shares, limit_price, stop_price)
            else:
                return self.order(sid, target, limit_price, stop_price)

        def order_target_value(self, sid, target, limit_price=None,
                               stop_price=None):
            """
            Place an order to adjust a position to a target value. If
            the position doesn't already exist, this is equivalent to placing a new
            order. If the position does exist, this is equivalent to placing an
            order for the difference between the target value and the
            current value.
            """
            if sid in self.context.portfolio.positions:
                current_position = self.context.portfolio.positions[sid].amount
                current_price = self.context.portfolio.positions[sid].last_sale_price
                current_value = current_position * current_price
                req_value = target - current_value
                return self.order_value(sid, req_value, limit_price, stop_price)
            else:
                return self.order_value(sid, target, limit_price, stop_price)

        def order_target_percent(self, sid, target, limit_price=None,
                                 stop_price=None):
            """
            Place an order to adjust a position to a target percent of the
            current portfolio value. If the position doesn't already exist, this is
            equivalent to placing a new order. If the position does exist, this is
            equivalent to placing an order for the difference between the target
            percent and the current percent.

            Note that target must expressed as a decimal (0.50 means 50\%).
            """
            if sid in self.context.portfolio.positions:
                current_position = self.context.portfolio.positions[sid].amount
                current_price = self.context.portfolio.positions[sid].last_sale_price
                current_value = current_position * current_price
            else:
                current_value = 0
            target_value = self.context.portfolio.portfolio_value * target

            req_value = target_value - current_value
            return self.order_value(sid, req_value, limit_price, stop_price)

        pass

    #class _TradingAlgorithm_ZiplineShim(zipline.TradingAlgorithm):
    #    '''auto-generates a context to use'''
    #    def initialize(this):
    #        #delay initialize until start of first handle-data, so our
    #        #portfolio object is available
    #        #this.__isInitialized = False;
    #        this.context = Shims.Context()
    #        this.context.tradingAlgorithm = this            
    #        #this.context.portfolio = this.portfolio
    #        pass

    #    def handle_data(this,data):      
    #        this.context.portfolio = this.portfolio
    #        #if not this.__isInitialized:
    #        #    this.__isInitialized=True
    #        #    this.context.portfolio=this.portfolio
                
    #        this.context.framework._update(data)
    #        pass
    #    pass

class FrameHistory:
    def __init__(this,parent,framework, data):
        this.parent = parent
        this.framework = framework
        this.state = []
        this.isActive = this.parent.isActive
        #this.maxHistoryFrames = this.framework.maxHistoryFrames
        #assert(this.framework.simFrame == this.parent.simFrame, "parent frame
        #does not match")
        
        this.initialize(data)
    
    def initialize(this, data):
        '''overridable'''
        logger.error("FrameHistory.initialize() invoked.  You should override this method.")
        pass

    def constructFrameState(this,data):
        '''override and return the frame state, this will be prepended to history
        if you return NONE, the frame state (history) is not modified.'''   
        logger.error("FrameHistory.constructFrameState() invoked.  You should override this method.")             
        pass

    def _update(this,data):
        this.isActive = this.parent.isActive
        if not this.isActive:
            return

        

        currentState = this.constructFrameState(data)
        if(currentState != None):
            currentState.datetime = this.framework._getDatetime()
            currentState.simFrame = this.framework.simFrame

            this.state.insert(0,currentState)
            del this.state[this.framework.maxHistoryFrames:]

class StrategyPosition:
    '''allows two or more stratgies to controll their own positions (orders) for securities they care about, 
    without interfering with the orders of other strategies.

    To use:   each strategy should set security.myStrategyPositon.targetCapitalSharePercent, which is a percentage of your entire portfolio's value
    then execute the order (and/or rebalance) by invoking security.myStrategyPosition.processOrder()
    '''

    def __init__(this, security, strategyName):            
        this._security = security
        this._strategyName = strategyName
        this._lastOrderId = 0
        this._lastStopOrderId = 0
        this._currentCapitalSharePercent = 0.0
        this._currentShares = 0
        #for the last trade roundtrip, the aproximate returns.  set every time our percent changes to zero
        this._lastRoundtripReturns = 0.0
        #this is editable
        this.targetCapitalSharePercent = 0.0
        #price when we decided to order, not actually the fulfillment price
        this.__lastOrderPrice = 0.0
        this.__currentPeakGains = 0.0
        this.__currentPeakGainsDecay = 0.0
        this._currentReturns = 0.0 #returns of current open position. 
        this._totalTrades = 0 #total trades we execute via this strategyPosition.  note that due to partial fills, this may be less than actual trades

    def processOrder(this, data, rebalanceThreshholdPercent=0.05, maxLosses=None, maxGainsAdditionalDrawdown=None, maxGainsDecay=0.01): #, OBSOLETE_stopLimitPercent=0.0, OBSOLETE_momentumStopLimit = True, OBSOLETE_decayMomentum = 0.001):
        ''' set rebalanceThreshholdPercent to zero (0.0) to cause the position to readjust even if the targetPercentage doesn't change.   this is useful for reinvesting divideds / etc
        but is set to 0.05 (5 percent) so we don't spam orders 
        
        maxLosses:  close if our open position suffers a loss of this percent or more
        maxGainsAdditionalDrawdown : close if our open position's gains suffer a decrease of this+maxLosses or more.
        maxGainsDecay : over time this will reduce the acceptable gains drawdown (specified by maxGainsAdditionalDrawdown) so that on long-running gains we don't incur such a large drawdown before closing.
        '''
        #if momentumStopLimit == True (the default) we will stopLimitPercent based on the peak gains, not based on the original purchase price (this is generally a good ideas as it will maximize your gains)
        #decayMomentum : = if == 0.01 and using momentumStopLimit==True, we will decay the position's survival chances by 1% per tick until it's finally closed.
        
        if this._currentCapitalSharePercent == 0.0 and this.targetCapitalSharePercent == 0.0:
            #no work to do
            return 0



        currentPrice = data[this._security.qsec].close_price
        
        if this._currentCapitalSharePercent == this.targetCapitalSharePercent and this._currentCapitalSharePercent != 0.0:
            #update current returns
            this._currentReturns = (currentPrice - this.__lastOrderPrice) / this.__lastOrderPrice * math.copysign(1.0,this._currentCapitalSharePercent)
        else:
            #target is different so reset our returns as we are about to change our order
            this._currentReturns = 0.0


        if this._currentCapitalSharePercent == this.targetCapitalSharePercent and maxGainsAdditionalDrawdown != None:
            ##handle maxGains stoplimits
            gainsPercent = this._currentReturns - this.__currentPeakGainsDecay
            #if gainsPercent < -maxLosses:
            #    #loosing, so close out
            #    logger.debug("loosing, so close out.  gainsPercent={0}, maxLosses={1}".format(gainsPercent, maxLosses))
            #    this.targetCapitalSharePercent = 0.0 
            #else:

            if this._currentReturns > this.__currentPeakGains:
                this.__currentPeakGains = this._currentReturns
                this.__currentPeakGainsDecay = 0.0 #reset decay 
            else:
                #need to see if our gain exceed our stoplimitGains threshhold
                gainsFloorThreshhold = this.__currentPeakGains * maxGainsAdditionalDrawdown
                if gainsPercent < gainsFloorThreshhold:
                    lossesFromPeak = this.__currentPeakGains - gainsPercent
                    if maxLosses != None and lossesFromPeak < maxLosses:
                        #we are not yet exceeding maxLosses (from our peak) so don't close out yet
                        logger.debug("we are not yet exceeding maxLosses (from our peak) so don't close out yet.  \t {0} @ {1}, gains={2}".format(this._security.symbol,currentPrice,this._currentReturns))
                        pass
                    else:
                        #loosing from our peak, so close out
                        logger.debug("loosing from our peak, so close out.  gainsPercent={0:.4f}, \t gainsFloorThreshhold={1:.4f}, \t  lossesFromPeak={2:.4f}, \t  maxLosses={3:.4f}  \t this._currentReturns={4:.4f}".format(gainsPercent, gainsFloorThreshhold, lossesFromPeak, maxLosses,this._currentReturns))
                        this.targetCapitalSharePercent = 0.0 

                this.__currentPeakGainsDecay += (this.__currentPeakGains * maxGainsDecay)
        else:
            this.__currentPeakGains = 0.0
            this.__currentPeakGainsDecay = 0.0

        if this._currentCapitalSharePercent == this.targetCapitalSharePercent and this._currentCapitalSharePercent != 0.0:
            #handle maxlosses stoplimit
            if maxLosses != None and this._currentReturns < -maxLosses:
                logger.debug("maxlosses stoplimit.  this._currentReturns={0}, maxLosses={1}".format(this._currentReturns, maxLosses))
                this.targetCapitalSharePercent = 0.0


           

        if this.targetCapitalSharePercent == 0.0 and this._currentCapitalSharePercent != 0.0:
            #record our expected PnL
            this._lastRoundtripReturns = this._currentReturns

        this._currentCapitalSharePercent = this.targetCapitalSharePercent
        
        
           
        #determine value of percent
        targetSharesValue = this._security.framework.context.portfolio.portfolio_value * this._currentCapitalSharePercent
        targetSharesTotal = int(math.copysign(math.floor(abs(targetSharesValue / currentPrice)),targetSharesValue))
        
        targetSharesDelta = targetSharesTotal - this._currentShares

        if targetSharesTotal != 0:
            if abs(targetSharesDelta / (targetSharesTotal * 1.0)) < rebalanceThreshholdPercent:
                #logger.debug("{0} ORDER SKIPPED! {1} (change to small) : {2} + {3} => {4} shares".format(this.strategyName,this.security.symbol, this.currentShares, targetSharesDelta, targetSharesTotal))          
                #our position change was too small so we skip rebalancing
                return

        #do actual order
        if(abs(targetSharesDelta) >= 1): #can not perform an order on less than 1 share
            ####cancel previous open order, if any  #doesn't really work, as even when canceling, some shares may be filled so you'll be left in an uncomplete state
            ###lastOrder = get_order(this.lastOrderId)
            ###unfilled = lastOrder.amount - l
            ###cancel_order(this.lastOrderId)
            logger.info("{0} order {1} : {2} + {3} => {4} shares  \t \t decisionPrice={5} ".format(this._strategyName,this._security.symbol, this._currentShares, targetSharesDelta, targetSharesTotal,currentPrice))          
            this._lastOrderId = this._security.framework.tradingAlgorithm.order(this._security.sid,targetSharesDelta,None,None)
            this._currentShares = targetSharesTotal
            this.__lastOrderPrice = currentPrice
            this._totalTrades += 1
            this._security.framework._totalTrades += 1
            
            return this._lastOrderId
        else:
            return 0

class Security:
    isDebug = False


    class QSecurity:
        '''
        Quantopian internal security object
        If you have a reference to a security object, there are several properties that might be useful:
            sid = 0 #Integer: The id of this security.
            symbol = "" #String: The ticker symbol of this security.
            security_name = "" #String: The full name of this security.
            security_start_date = datetime.datetime() #Datetime: The date when this security first started trading.
            security_end_date = datetime.datetime() #Datetime: The date when this security stopped trading (= yesterday for securities that are trading normally, because that's the last day for which we have historical price data).
        '''
        def __init__(this):
            this.sid = 0 #Integer: The id of this security.
            this.symbol = "" #String: The ticker symbol of this security.
            this.security_name = "" #String: The full name of this security.
            this.security_start_date = datetime.datetime(1990,1,1) #Datetime: The date when this security first started trading.
            this.security_end_date = datetime.datetime(1990,1,1) #Datetime: The date when this security stopped trading (= yesterday for securities that are trading normally, because that's the last day for which we have historical price data).
    
    

    def __init__(this,sid, framework):
        this.sid = sid  
        this.isActive = False
        this.framework = framework
        this.security_start_date = datetime.datetime.utcfromtimestamp(0)
        this.security_end_date = datetime.datetime.utcfromtimestamp(0)
        this.simFrame = -1
        this.security_start_price = 0.0
        this.security_end_price = 0.0
        #this.daily_open_price = [0.0]
        #this.daily_close_price = [0.0]
        this.symbol = "??? Not yet active so symbol not known"
        
        
    def getCurrentPosition(this):
        if this.simFrame == -1:
            return Shims.Position()
        return this.framework.context.portfolio.positions[this.qsec]

    def update(this,qsec, data):
        '''qsec is only given when it's in scope, and it can actually change each timestep 
        what it does:
        - construct new state for this frame
        - update qsec to most recent (if any)
        '''
        #update our tickcounter, mostly for debug
        this.simFrame = this.framework.simFrame
        #assert(this.simFrame >= 0,"security.update() frame not set")

        
        
        #update qsec to most recent (if any) 67
        this.qsec = qsec
        if qsec:
            this.isActive = True
            this.symbol = qsec.symbol
            #assert(qsec.sid == this.sid,"security.update() sids do not match")
            
            if this.security_start_price == 0.0:
                this.security_start_price = data[this.sid].close_price
            this.security_end_price = data[this.sid].close_price

            this.security_start_date = qsec.security_start_date
            this.security_end_date = qsec.security_end_date
        else:
            this.isActive = False

        #try:
        #    this.daily_close_price =
        #    this.framework.daily_close_price[this.qsec]
        #    this.daily_open_price = this.framework.daily_open_price[this.qsec]
        #except:
        #    this.daily_close_price = []
        #    this.daily_open_price = []

        #if len(this.daily_close_price) == 0 or len(this.daily_open_price) ==
        #0:
        #    this.isActive = False
class FrameworkBase():
    def __init__(this, context, data, maxHistoryFrames=60): #5 days of history
        this.maxHistoryFrames = maxHistoryFrames
        this.__isFirstTimestepRun = False
        this.context = context
        this.tradingAlgorithm = Shims._TradingAlgorithm_QuantopianShim() #prepopulate to allow intelisence
        this.tradingAlgorithm = context.tradingAlgorithm
        this.simFrame = -1 #the current timestep of the simulation
        this.framesToday = -1 #number of frames executed today.  naturally only useful in intraday mode
        
        this.allSecurities = {} #dictionary of all securities, including those not targeted
        
        this.activeSecurities = {}

        #stub for intelisence propigation.  without this, visual studio doesn't properly identify the types contained.
        this.allSecurities["1"]=Security(0,this)
        this.allSecurities.clear()


        this.thisFrameDay = 0
        this.lastFrameDay = 0

        this._totalTrades = 0 #total trades we execute via all strategyPositions.  note that due to partial fills, this may be less than actual trades

        this.isIntradayRunDetected = False #if we are running in intraday, this will be set to true on frame 2.  the 2nd bar will be in the same day as the first bar.  no better way to detect unfortunately.

        #for storing quantopian history
        #this.daily_close_price = pandas.DataFrame()
        #this.daily_open_price = pandas.DataFrame()
        
        this._initialize(data)

        pass
    def ensureMinHistory(this, minFrames):
        '''increases the history frames if the current is less than your required min.  
        this is a good way to set your history, as too much history will slow down your sim, and can crash it due to out-of-memory'''

        if this.maxHistoryFrames < minFrames:
            this.maxHistoryFrames = minFrames      
    
    def _initialize(this, data):
        '''starts initialiation of the framework
        do not override this, or any other method starting with an underscore.
        methods without an underscore prefix can and should be overridden.'''
        #do init here
        this.initialize(data)        
        pass

    def initialize(this, data):
        '''override this to do your init'''
        logger.error("You should override FrameworkBase.initialize()")
        pass


    def initializeFirstUpdate(this,data):
        '''override this.  called the first timestep, before update.  
        provides access to the 'data' object which normal .initialize() does not'''
        logger.error("You should override FrameworkBase.initializeFirstUpdate()")
        pass

    def _update(this,data):

        '''invoked by the tradingAlgorithm shim every update.  internally we will call abstract_update_timestep_handle_data()
        DO NOT OVERRIDE THIS OR ANY METHODS STARTING WITH AN UNDERSCORE
        override methods without underscores.
        '''
        
        #frame updates
        #this.data = data

        this.simFrame+=1        
        
        this.lastFrameDay = this.thisFrameDay
        this.thisFrameDay = this._getDatetime().day

        
        #supdating our history once per day
        if(this.thisFrameDay != this.lastFrameDay):
            #only update this once per day, hopefully improving performance...
            #this.daily_close_price = history(bar_count=180, frequency='1d',
            #field='close_price')
            #this.daily_open_price = history(bar_count=180, frequency='1d',
            #field='open_price')
            this.framesToday = 0
        else:
            this.framesToday += 1
            this.isIntradayRunDetected = True

        this.__updateSecurities(data)
        

        if not this.__isFirstTimestepRun:
            this.__isFirstTimestepRun = True
            this.initializeFirstUpdate(data)

        this.update(data)
        pass

    def update(this,data):
        '''override and update your usercode here'''
        logger.error("You should override FrameworkBase.update()")
        pass

    def __updateSecurities(this,data):
        '''get all qsecs from data, then update the targetedSecurities accordingly'''
        #logger.debug("FrameworkBase.__updateSecurities() start.
        #allSecLength={0}".format(len(this.allSecurities)))
        #convert our data into a dictionary
        currentQSecs = {}
        newQSecs = {}
        for qsec in data:            
            #if online, qsec is a securities object
            sid = qsec.sid      
            
            #logger.debug("FrameworkBase.__updateSecurities() first loop, found
            #{0}, sid={1}.  exists={2}".format(qsec,
            #sid,this.allSecurities.has_key(sid) ))

            currentQSecs[sid] = qsec
            #determine new securities found in data
            if not this.allSecurities.has_key(sid):
                logger.debug("FrameworkBase.__updateSecurities() new security detected.  will construct our security object for it: {0}".format(qsec))
                newQSecs[sid] = qsec


        #construct new Security objects for our newQSecs
        for sid, qsec in newQSecs.items():            
            #assert(not
            #this.allSecurities.has_key(sid),"frameworkBase.updateSecurities
            #key does not exist")
            #logger.debug("FrameworkBase.__updateSecurities() new security
            #found {0}".format(qsec))
            security = this._getOrCreateSecurity(qsec, data)
            this.allSecurities[security.sid] = security

        newQSecs.clear()

        #update all security objects, giving a null qsec if one doesn't exist
        #in our data dictionary
        for sid, security1 in this.allSecurities.items():
            qsec = currentQSecs.get(sid)
            security1.update(qsec, data)

        ## determine active securities set.
        this.activeSecurities.clear()
        for sid,security2 in this.allSecurities.items():
            if not security2.isActive:
                #logger.debug("FrameworkBase.__updateSecurities() NOT ACTIVE
                #{0}".format(security.qsec))
                continue
            #logger.debug("FrameworkBase.__updateSecurities() ACTIVE
            #{0}".format(security.qsec))
            this.activeSecurities[sid] = security2
            pass

        pass

    def initializeSecurity(this,security, data):
        '''override to do custom init logic on each security. 
        if you wish to use your own security, return it (it will replace the existing)'''
        logger.error("You should override FrameworkBase.initializeSecurity()")
        pass       
             
    def _getOrCreateSecurities(this,qsecArray, data):
        '''pass in an array of quantopian sid/sec tuples  (ex:  [(24,sid(24)),(3113,sid(3113))]) 
        and returns an array of unique security objects wrapping them.   duplicate sids are ignored'''

        securities = {}

        for qsec in qsecArray:            
            security = this._getOrCreateSecurity(qsec, data)
            securities[security.sid] = security
            pass

        return securities.values()

    def _getOrCreateSecurity(this, qsec, data):
        '''pass in a quantopian sec (ex:  sid(24)) and returns our security object wrapping it
        if the security object
        '''
        
        sid = qsec.sid
        if this.allSecurities.has_key(sid):
            return this.allSecurities[sid]

        #does not exist, have to create
        newSecurity = Security(sid,this)
        #new, so do our framework's custom init logic on this security
        maybeNewSec = this.initializeSecurity(newSecurity, data)
        if maybeNewSec is not None:
            #framework replaced newSec with a different sec
            newSecurity = maybeNewSec
                
        this.allSecurities[sid] = newSecurity
        
        return newSecurity
        pass


    def _getDatetime(this):
        '''returns current market time, using US/Eastern timezone'''
        return pandas.Timestamp(pandas.Timestamp(get_datetime()).tz_convert('US/Eastern'))
#entrypoints

def handle_data(context=Shims.Context(),data=pandas.DataFrame()):   
    '''update method run every timestep on quantopian'''
    
    #try: 
    if context.firstFrame:
        #'''init on our first frame'''
        context.firstFrame = False
        context.tradingAlgorithm = Shims._TradingAlgorithm_QuantopianShim()
        context.tradingAlgorithm.context = context
        context.framework = constructFramework(context,data)
        
    
    context.framework._update(data)
    #except Exception,e:
    #    print "Caught:",e

    pass

class Global():
    pass
global _g
_g = Global()




def initialize(context=Shims.Context()):
    '''initialize method used when running on quantopian'''
    context.firstFrame = True 
    
    _g.context = context
    #context.spy = sid(8554) #SPY
    ########## SET UNIVERSE
    #if you need set universe, do it here (note that doing this slows the algo
    #considerably)
    set_universe(universe.DollarVolumeUniverse(floor_percentile=90.0,ceiling_percentile=100.0))
    #context.universe = [#sid(698)         #BA
    #    #sid(8554) #SPY
    #    #sid(27098) #ISE

    #    ####################### 9 sector etfs
    #    sid(19662) # XLY Consumer Discrectionary SPDR Fund
    #    ,sid(19656) # XLF Financial SPDR Fund
    #    ,sid(19658) # XLK Technology SPDR Fund
    #    ,sid(19655) # XLE Energy SPDR Fund
    #    ,sid(19661) # XLV Health Care SPRD Fund
    #    ,sid(19657) # XLI Industrial SPDR Fund
    #    ,sid(19659) # XLP Consumer Staples SPDR Fund
    #    ,sid(19654) # XLB Materials SPDR Fund
    #    ,sid(19660) # XLU Utilities SPRD Fund
    #    ]

    #aprox 200 SPY constituents from fetcher
    #fetch_csv(
    #   "https://googledrive.com/host/0BwZ2bMDOKaeDYWYzYzgxNDYtNmQyYi00ZDk5LWE3ZTYtODQ0ZDAzNTBkY2M4/trading/SP500-20131001.csv",
    #    pre_func=preview,
    #    date_column='date',
    #    universe_func=(my_universe))
    #aprox 90 hardcoded SPY constituents
    #my_static_universe(context) 

    ########## COMMISSION
    #use top to decrease uncertainty when testing algorithms
    #set_commission(commission.PerShare(cost=0.0))
    #set_commission(commission.PerShare(cost=0.005, min_trade_cost=1.00)) #IB
    #fixed commission model
    #set_commission(commission.PerShare(cost=0.013, min_trade_cost=1.3)) #more
    #agressive...
    
    ########## SLIPPAGE
    #use top to decrease uncertainty when testing algorithms
    #set_slippage(slippage.FixedSlippage(spread=0.00))
    #set_slippage(slippage.FixedSlippage(spread=0.01))
    #set_slippage(WorstSpreadSlippage())
    #set_slippage(CustomSlippage(1.0,0.0))

    ############# Anony values
    set_commission(commission.PerTrade(cost=1.0))
    set_slippage(TradeAtTheOpenSlippageModel_Simple(0.1))

##############  USERCODE BELOW.  EDIT BELOW THIS LINE
##############  USERCODE BELOW.  EDIT BELOW THIS LINE
##############  USERCODE BELOW.  EDIT BELOW THIS LINE


class BBTechnicalIndicators(FrameHistory):
    '''technical indicators relating to bollinger bands'''
    class State:
        '''State recorded for each frame (minute).  number of frames history we store is determined by framework.maxHistoryFrames'''
        def __init__(this,parent, security, data):
            this.parent = parent
            this.security = security
            this.history = this.parent.state

            bb = this.parent.bbands_data[this.security.sid]
            #will be NaN if not enough period
            this.upperLimit = bb[0]
            this.line = bb[1]
            this.lowerLimit = bb[2]
            #see https://www.tradingview.com/stock-charts-support/index.php/Bollinger_Bands_%25B_(%25B)
            this.percentB = (this.security.standardIndicators.state[0].close_price - this.lowerLimit) / (this.upperLimit - this.lowerLimit)
            #see https://www.tradingview.com/stock-charts-support/index.php/Bollinger_Bands_Width_(BBW)
            this.bbw = (this.upperLimit - this.lowerLimit) / this.line
            #track slope of %B, to determine if rising (positive) or falling (negative)
            if len(this.history) > 0:
                this.percentBSlope = (this.percentB - this.history[0].percentB)
                this.bbwSlope = (this.bbw - this.history[0].bbw)
                this.percentBPercentile = scipy.stats.percentileofscore([state.percentB for state in this.history],this.percentB,"mean") / 100.0
                this.bbwPercentile = scipy.stats.percentileofscore([state.bbw for state in this.history],this.bbw,"mean") / 100.0 
                this.lineSlope = (this.line - this.history[0].line)
            else:
                this.percentBSlope = 0.0
                this.bbwSlope = 0.0
                this.percentBPercentile = 0.5
                this.bbwPercentile = 0.5
                this.lineSlope = 0.0

            #track momentum
            if this.percentB > 0.8:
                if len(this.history) > 0:
                    this.upperMomentumTicks = this.history[0].upperMomentumTicks + 1
                else:
                    this.upperMomentumTicks = 1
            else:
                this.upperMomentumTicks = 0            
            if this.percentB < 0.2:
                if len(this.history) > 0:
                    this.lowerMomentumTicks = this.history[0].lowerMomentumTicks + 1
                else:
                    this.lowerMomentumTicks = 1
            else:
                this.lowerMomentumTicks = 0





            #logger.debug(" bb for {0} is {1}".format(this.security.symbol, bb));
            
            #logger.recordNormalized("upperLimit",this.upperLimit,this.security.security_start_price)
            #logger.recordNormalized("line",this.line,this.security.security_start_price)
            #logger.recordNormalized("lowerLimit",this.lowerLimit,this.security.security_start_price)

            #logger.record("upperBar",1.0)
            #logger.record("lowerBar",0.0)
            #logger.record("upperApproach",0.8)
            #logger.record("lowerApproach",0.2)
            #logger.record("percentB",this.percentB);

        def __repr__(this):
            return "{0} @ {1} BBANDS l={2:.2f} \t upper={3:.2f} lower={4:.2f}".format(this.security.symbol, this.datetime, this.line, this.upperLimit, this.lowerLimit)


    def initialize(this, data):
        this.bbands = ta.BBANDS(timeperiod=20,nbdevup=2, nbdevdn=2,matype=0) #output: Dictionary of sid to tuples, where each tuple is three floats: (upperLimit, line, lowerLimit).
        this.bbands_data = this.bbands(data)
        pass
    
    def constructFrameState(this,data):
        #logger.debug("BBTechnicalIndicators.constructFrameState")
        currentState = BBTechnicalIndicators.State(this, this.parent, data)
        return currentState

class StandardIndicators(FrameHistory):
    '''common technical indicators that we plan to use for any/all strategies
    feel free to extend this, or use as a reference for constructing specialized technical indicators'''
    class State:
        '''State recorded for each frame (minute).  number of frames history we store is determined by framework.maxHistoryFrames'''
        def __init__(this,parent, security, data):
            this.parent = parent
            this.security = security
            this.history = this.parent.state

            #preset for proper intelisence
            this.datetime = datetime.datetime.now()
            this.open_price = 0.0
            this.close_price = 0.0
            this.high = 0.0
            this.low = 0.0
            this.volume = 0

            #this.mavg3 = 0.0
            #this.mavg7 = 0.0
            #this.mavg15 = 0.0
            #this.mavg30 = 0.0
            #this.mavg45 = 0.0
            #this.mavg60 = 0.0

            #this.stddev3 = 0.0
            #this.stddev7 = 0.0
            #this.stddev15 = 0.0
            #this.stddev30 = 0.0
            #this.stddev45 = 0.0
            #this.stddev60 = 0.0

            this.datetime = data[this.security.qsec].datetime
            this.open_price = data[this.security.qsec].open_price
            this.close_price = data[this.security.qsec].close_price
            this.high = data[this.security.qsec].high
            this.low = data[this.security.qsec].low
            this.volume = data[this.security.qsec].volume
                        
            
            #mavg for last x minutes
            #this.mavg3 = numpy.mean([state.close_price for state in
            #this.history[0:3]])
            #this.mavg7 = numpy.mean([state.close_price for state in
            #this.history[0:7]])
            #this.mavg15 = numpy.mean([state.close_price for state in
            #this.history[0:15]])
            #this.mavg30 = numpy.mean([state.close_price for state in
            #this.history[0:30]])
            #this.mavg45 = numpy.mean([state.close_price for state in
            #this.history[0:45]])
            #this.mavg60 = numpy.mean([state.close_price for state in
            #this.history[0:60]])

            #this.stddev3 = numpy.std([state.close_price for state in
            #this.history[0:3]])
            #this.stddev7 = numpy.std([state.close_price for state in
            #this.history[0:7]])
            #this.stddev15 = numpy.std([state.close_price for state in
            #this.history[0:15]])
            #this.stddev30 = numpy.std([state.close_price for state in
            #this.history[0:30]])
            #this.stddev45 = numpy.std([state.close_price for state in
            #this.history[0:45]])
            #this.stddev60 = numpy.std([state.close_price for state in
            #this.history[0:60]])

            if len(this.history) < 1:                
                this.returns = 0.0
                this.returns_median_abs = 0.0
            else:
                #always returns compared to last timestep
                this.returns = (this.close_price - this.history[0].close_price) / this.history[0].close_price
                if len(this.history) == 1:
                    this.returns_median_abs = abs(this.returns)
                else:
                    this.returns_median_abs = numpy.median([abs(state.returns) for state in this.history])

            try:                
                #when in intraday mode, stores cumulative returns through the day
                this.returns_today = data[this.security.qsec].returns()
            except:
                this.framework.logger.error("{0} unable to obtain returns()  setting returns to zero  open={1}.  close = {2}".format(this.parent.qsec, this.open_price, this.close_price))
                this.returns_today = 0.0
            pass

            #daily accumulations
            if this.security.framework.thisFrameDay != this.security.framework.lastFrameDay or len(this.history) < 1:
                this.open_price_today = this.open_price
                #if len(this.history) < 1:
                    
                #    this.open_price_yesterday = this.open_price_today
                #    this.close_price_yesterday = this.close_price
                #    this.returns_yesterday = this.returns_today
                ##new day, so record our start of day values
                #else:
                #    this.open_price_yesterday =
                #    this.history[0].open_price_today
                #    this.close_price_yesterday = this.history[0].close_price
                #    this.returns_yesterday = this.history[0].returns_today
            else:
                this.open_price_today = this.history[0].open_price_today
                #this.open_price_yesterday =
                #this.history[0].open_price_yesterday
                #this.close_price_yesterday =
                #this.history[0].close_price_yesterday
                #this.returns_yesterday = this.history[0].returns_yesterday

        def __repr__(this):
            return "{0} @ {1} c={0}".format(this.security.symbol, this.datetime, this.close_price)

    def initialize(this, data):
        pass
    
    def constructFrameState(this,data):
        #logger.debug("StandardTechnicalIndicators.constructFrameState")
        currentState = StandardIndicators.State(this, this.parent, data)
        return currentState


class DailyTechnicalIndicators(FrameHistory):
    '''standard technical indicators for the entire day
    for daily history.   the .state[] history does not include the current day, only previous days'''
    class State:
        '''State recorded for each previous day.  number of frames history we store is determined by framework.maxHistoryFrames'''
        def __init__(this,parent, security, data):
            this.parent = parent
            this.security = security
            this.history = this.parent.state



            #preset for proper intelisence
            this.datetime = datetime.datetime.now()


            #setting these to default to yesterday's value so that for the
            #first day of our simulation we get reasonable values
            this.open_price = data[this.security.qsec].mavg(1)
            this.close_price = this.open_price
            #this.high = 0.0
            #this.low = 0.0
            #this.volume = 0

            #this.mavg3 = this.open_price
            #this.mavg7 = this.open_price
            #this.mavg15 = this.open_price
            #this.mavg30 = this.open_price
            #this.mavg45 = this.open_price
            #this.mavg60 = this.open_price

            #this.stddev3 = this.open_price
            #this.stddev7 = this.open_price
            #this.stddev15 = this.open_price
            #this.stddev30 = this.open_price
            #this.stddev45 = this.open_price
            #this.stddev60 = this.open_price

            
            if this.security.simFrame != 0:
                #assert(this.security.standardIndicators.state[1].simFrame+1 ==
                #this.security.simFrame,"expect to be previous day")
            
                this.datetime = this.security.standardIndicators.state[1].datetime
                this.open_price = this.security.standardIndicators.state[1].open_price_today
                this.close_price = this.security.standardIndicators.state[1].close_price
                this.returns = this.security.standardIndicators.state[1].returns_today

            
            #mavg for last x days
            #this.mavg3 = data[this.security.qsec].mavg(3)
            #this.mavg7 = data[this.security.qsec].mavg(7)
            #this.mavg15 = data[this.security.qsec].mavg(15)
            #this.mavg30 = data[this.security.qsec].mavg(30)
            #this.mavg45 = data[this.security.qsec].mavg(45)
            #this.mavg60 = data[this.security.qsec].mavg(60)

            #this.stddev3 = data[this.security.qsec].stddev(3)
            #this.stddev7 = data[this.security.qsec].stddev(7)
            #this.stddev15 = data[this.security.qsec].stddev(15)
            #this.stddev30 = data[this.security.qsec].stddev(30)
            #this.stddev45 = data[this.security.qsec].stddev(45)
            #this.stddev60 = data[this.security.qsec].stddev(60)

        def __repr__(this):
            return "c={0} mavg7={1} mavg30={2}".format(this.close_price,this.mavg7,this.mavg30)

    def initialize(this, data):
        pass
    
    def constructFrameState(this,data):
        #logger.debug("StandardTechnicalIndicators.constructFrameState")

        if this.framework.thisFrameDay == this.framework.lastFrameDay:
            #keep previous
            currentState = None
        else:
            currentState = DailyTechnicalIndicators.State(this, this.parent, data)

        return currentState
    pass



class VolatilityBiasIndicators(FrameHistory):
    ''' custom indicators used by the volatility bias strategy '''
    def initialize(this, data):
        
        pass
    
    def setWindow(this, trendPeriods, weightPeriods, triggerPeriods):
        '''set the size of the window our volatilityBias cares about
        trendPeriods #state.trend = percent the range is up, exponential weighted by timestep
        weightPeriods #state.weight = percent the range is up, linear weighted by timestep
        triggerPeriods #state.trigger = percent the range is up, linear weighted by timestep
        '''

        #internal variables
        this.trendPeriods = trendPeriods #the max history we will care about, used for determining the value of the state.trend variable
        this.weightPeriods = weightPeriods
        this.triggerPeriods = triggerPeriods
        
        this.framework.ensureMinHistory(this.trendPeriods)
        this.framework.ensureMinHistory(this.weightPeriods)
        this.framework.ensureMinHistory(this.triggerPeriods)

    '''technical indicators relating to bollinger bands'''
    class State:
        '''State recorded for each frame (minute).  number of frames history we store is determined by framework.maxHistoryFrames'''
        def __init__(this,parent, security, data):
            this.parent = parent
            this.security = security
            this.history = this.parent.state

            

            this.setWeight()

        def setWeight(this):
            '''computes weight by taking the price range (high-low) for each timestep, and summing them based on linear weight (most recient = more weight)'''
            #pretty confident in this port being accurate
            security = this.security
            stdState = security.standardIndicators.state
            stdStateLen = len(stdState)

            #set default values
            if len(this.history)== 0:
                this.weight = 0.0
                this.trend = 0.0
                this.trigger = 0.0
                return
            else:
                #set initial value equal to previous values
                this.weight = this.history[0].weight
                this.trend = this.history[0].trend
                this.trigger = this.history[0].trigger

            #SET state.trend
            #trading range linear weighted by timestep
            upPortion = 0.0
            downPortion = 0.0
            span = this.parent.trendPeriods if stdStateLen > this.parent.trendPeriods else stdStateLen
            for i in range(0,span):
                if stdState[i].close_price > stdState[i].open_price:
                    upPortion += ((span-i) * (stdState[i].high - stdState[i].low));  
                else:
                    downPortion +=((span-i) * (stdState[i].high - stdState[i].low));  
            if (upPortion + downPortion > 0.0):
                factor = upPortion / (upPortion + downPortion)
                #trend = percent the range is up, exponential weighted by timestep
                this.trend = (this.history[0].trend + factor) / 2.0
            #logger.info("sec={0} \t span={1} upP={2} dwnP={3} fac={4} trend={5}".format(this.security.symbol,span,upPortion,downPortion, factor, this.trend))
            #SET state.weight
            if stdStateLen > this.parent.weightPeriods:                
                upPortion = 0.0
                downPortion = 0.0
                span = this.parent.weightPeriods
                for i in range(0,span):
                    if stdState[i].close_price > stdState[i].open_price:
                        upPortion += ((span-i) * (stdState[i].high - stdState[i].low));  
                    else:
                        downPortion +=((span-i) * (stdState[i].high - stdState[i].low));  
                if (upPortion + downPortion > 0.0):
                    factor = upPortion / (upPortion + downPortion)
                    #weight = percent the range is up, linear weighted by timestep
                    this.weight = factor

            #SET state.trigger
            if stdStateLen > this.parent.triggerPeriods:                
                upPortion = 0.0
                downPortion = 0.0
                span = this.parent.triggerPeriods
                for i in range(0,span):
                    if stdState[i].close_price > stdState[i].open_price:
                        upPortion += ((span-i) * (stdState[i].high - stdState[i].low));  
                    else:
                        downPortion +=((span-i) * (stdState[i].high - stdState[i].low));  
                if (upPortion + downPortion > 0.0):
                    factor = upPortion / (upPortion + downPortion)
                    #trigger = percent the range is up, linear weighted by timestep
                    this.trigger = factor

            return this.weight

        def __repr__(this):
            return "{0} @ {1} VOLBIAS weight={2:.2f} \t trend={3:.2f} trigger={4:.2f}".format(this.security.symbol, this.datetime, this.weight, this.trend, this.trigger)
            


    
    def constructFrameState(this,data):
        #logger.debug("VolatilityBiasIndicators.constructFrameState")
        currentState = VolatilityBiasIndicators.State(this, this.parent, data)
        return currentState    

class VolatilityBiasStrategy():
    def __init__(this, framework, data):
        this.framework = framework


        pass

    def initialize(this,data):
        
        this.trendPeriods = 53
        this.weightPeriods = 33
        this.triggerPeriods = 4

        #this.universe = this.framework._getOrCreateSecurities([
        #    sid(12915) # MDY SPDR S&P MIDCAP 400 ETF TRUST
        #    ,sid(19654) # XLB Materials Select Sector SPDR 
        #    ,sid(19655) # XLE Energy Select Sector SPDR
        #    ,sid(19656) # XLF Financial Select Sector SPDR 
        #    ,sid(19657)# XLI Industrial Select Sector SPDR
        #    ,sid(19658)#XLK  Industrial Select Sector SPDR
        #    ,sid(19659) # XLP  Consumer Staples Select Sector SPDR
        #    ,sid(19660)# XLU Utilities Select Sector SPDR
        #    ,sid(19661)# XLV Utilities Select Sector SPDR
        #    ,sid(19662) # XLY Consumer Discretionary Select Sector SPDR
        #    ,sid(25485) # AGG ISHARES CORE U.S. AGGREGATE BONDS
        #    ],data)

    #    this.universe = this.framework._getOrCreateSecurities([
    #        sid(19920) # QQQ
    #        , sid(2174) # DIA
    #        , sid(24705) # ISHARES MSCI EMERGING MARKETS "EEM"
    #        , sid(22972) # ISHARES MSCI EAFE ETF "EFA"
    #        , sid(24744) # GUGGENHEIM S&P 500 EQUAL WEIGH "RSP",
    #        , sid(19654) # Materials Select Sector SPDR              "XLB"
    #        , sid(19655) # Energy Select Sector SPDR                 "XLE"
    #        , sid(19656) # Financial Select Sector SPDR              "XLF"
    #        , sid(19657) # Industrial Select Sector SPDR             "XLI"
    #        , sid(19658) # Technology Select Sector SPDR            "XLK"
    #        , sid(19659) # Consumer Staples Select Sector SPDR        "XLP"
    #        , sid(19660) # Utilities Select Sector SPDR              "XLU"
    #        , sid(19661) # Healthcare Select Sector SPDR            "XLV"
    #        , sid(19662) # Consumer Discretionary Select Sector SPDR "XLY"
    #        , sid(22739) # VANGUARD TOTAL STOCK MARKET ETF "VTI"
    #        , sid(25901) # VANGUARD SMALL-CAP VALUE ETF "VBR"
    #        , sid(25485) # ISHARES CORE U.S. AGGREGATE BONDS "AGG"
     
    #        ,  sid(2)     #   Alcoa "AA"
    #        , sid(679)   #   Amex "AXP"
    #        ,  sid(698)   #   BOEING CO   "BA"
    #        , sid(700)   #   BANK OF AMERICA CORP   "BAC"
    #        , sid(734)   #   BAXTER INTERNATIONAL INC   "BAX"
    #        , sid(1267)  #   CATERPILLAR INC   "CAT"
    #        ,sid(1900)  #   CISCO SYSTEMS INC   "CSCO"
    #        , sid(23112) #   CHEVRON CORPORATION   "CVX"
    #        ,  sid(2119)  #   DU PONT DE NEMOURS E I &CO   "DD"
    #        , sid(2190)  #   WALT DISNEY CO-DISNEY COMMON   "DIS"
    #        , sid(8347)  #   EXXON MOBIL CORPORATION          "XOM"
    #        ,  sid(3149)  #   GENERAL ELECTRIC CO     "GE"
    #        ,  sid(3496)  #   HOME DEPOT INC  "HD"
    #        , sid(3735)  #   HEWLETT-PACKARD CO   "HPQ"
    #        , sid(3766)  #   INTL BUSINESS MACHINES CORP   "IBM"
    #        ,sid(3951)  #   INTEL CORP   "INTC"
    #        , sid(4151)  #   JOHNSON AND JOHNSON   "JNJ"
    #        , sid(25006) #   JPMORGAN CHASE & CO COM STK   "JPM"
    #        ,  sid(4283)  #   COCA-COLA CO   "KO"
    #        , sid(4707)  #   MCDONALDS CORP   "MCD"
    #        , sid(4922)  #   3M COMPANY   "MMM"
    #        , sid(5029)  #   MERCK & CO IN C  "MRK"
    #        ,sid(5061)  #   MICROSOFT CORP   "MSFT"
    #        , sid(5923)  #   PFIZER INC   "PFE"
    #        ,  sid(5938)  #   PROCTER & GAMBLE CO   "PG"
    #        ,   sid(6653)  #   AT&T INC.COM   "T"
    #        , sid(24845) #   Travelers "TRV"
    #        , sid(7792)  #   UNITEDHEALTH GROUP INC  "UNH"
    #        , sid(7883)  #   UNITED TECHNOLOGIES CORP   "UTX"
    #        ,  sid(21839) #   VERIZON COMMUNICATIONS   "VZ"
    #        , sid(8229)  #   WAL-MART STORES INC  "WMT"
    #],data)

    def update(this, data):
        
        if this.framework.simFrame < (this.weightPeriods -1):
            #ensure we have our history populated
            return

        totalWeight = 0
        entries = [] #securities we will open positions with
        exits = [] #open positions we will close

        securitiesToEnumerate = this.framework.activeSecurities.items()

        for sid,security in securitiesToEnumerate:
            enter = False
            exit = False
            if security.isActive==False:
                continue

            volBiasState = security.volBiasIndicators.state[0]
            
            if volBiasState.weight - volBiasState.trigger >= 0.40 and volBiasState.trend > 0.50:
                enter = True
            elif security.volatilityBiasStrategyPosition._currentCapitalSharePercent > 0.0:
                if volBiasState.trigger > 0.50 and volBiasState.trigger < 0.80:
                    enter = True
                else: 
                    exit = True
            else:
                exit = True

            if enter:                
                totalWeight += volBiasState.weight
                entries.append(security)
            if exit:
                exits.append(security)
                pass
            pass
        enterCount = len(entries)
        if enterCount > 0:
            for security in entries:
                #rebalance based on weights
                security.volBiasIndicators.state[0].weight /= totalWeight
                security.volatilityBiasStrategyPosition.targetCapitalSharePercent = security.volBiasIndicators.state[0].weight
        for security in exits:
            security.volatilityBiasStrategyPosition.targetCapitalSharePercent = 0.0
            pass

        for sid,security in securitiesToEnumerate:
            #execute trades for this timestep
            security.volatilityBiasStrategyPosition.processOrder(data)
            
        #logger.record("Weight",this.universe[0].volBiasIndicators.state[0].weight)
        #logger.record("Trigger",this.universe[0].volBiasIndicators.state[0].trigger)
        #logger.record("Trend",this.universe[0].volBiasIndicators.state[0].trend)
            
       



    
    
class ExampleFramework(FrameworkBase):
    def initialize(this, data):
        
        this.volatilityBiasStrategy = VolatilityBiasStrategy(this,data)
        this.volatilityBiasStrategy.initialize(data)
        
        #this.spy = this._getOrCreateSecurity(sid(8554), data) #SPY
        

        pass

    def initializeFirstUpdate(this, data):
        #this.ensureMinHistory(360)
        pass

    def initializeSecurity(this,security, data):
        security.standardIndicators = StandardIndicators(security,this, data)
        #security.dailyIndicators = DailyTechnicalIndicators(security,this)
        security.volBiasIndicators = VolatilityBiasIndicators(security,this, data)
        #set our securities to use the same window sizes based on a global config
        security.volBiasIndicators.setWindow(this.volatilityBiasStrategy.trendPeriods, this.volatilityBiasStrategy.weightPeriods, this.volatilityBiasStrategy.triggerPeriods)
        security.volatilityBiasStrategyPosition = StrategyPosition(security,"volatilityBiasStrategyPosition")
        
        
        pass

    def update(this, data):
        #update all security indicators
        for sid,security in this.activeSecurities.items():
            security.standardIndicators._update(data)
            #security.dailyIndicators._update(data)
            security.volBiasIndicators._update(data)
            pass

        this.volatilityBiasStrategy.update(data)

    pass





##############  CONFIGURATION BELOW
def constructFramework(context,data):
    '''factory method to return your custom framework/trading algo'''
    return ExampleFramework(context,data)

There was a runtime error.

Took a stab at converting this to minute mode while maintaining the analysis/execution on a daily basis. Here's what I've changed:

  • No custom slippage - uses default slippage
  • The analysis is still done daily, but at a time that can be (eventually) controlled: right now, security manager update is done once a day early during trading. If any orders are to be placed, they're placed at the same time early in the day (this can be modified to place buy orders early and sell orders nearer to close times etc)
  • For the analysis, it calls on the history function to load the previous day's final ohlc data.
  • Modified the security manager to take symbols instead of sids (my own preference really and to understand when some securities started - will set back to sid for the next run)
  • Set the start date to 2008/3/19 - to account for unique symbols and shorter for quicker results (will go farther back with sids instead of symbols)
  • Capital_base set to $10k instead of $100k. I had noticed higher returns with larger starting capital in daily tests.

Otherwise, I've kept all else the same. Still needs a weightPeriods warm up etc. This backtest took under 2 hours to run. While survivor bias is important to eliminate, this particular minute mode implementation behaves like a robust defensive strategy, at least. Comparing to daily mode, and at the risk of stating the obvious with most investments, sensitivity to entry/exit plays a major role.

Clone Algorithm
35
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 collections import deque
import pytz

trendPeriods = 53
weightPeriods = 33
triggerPeriods = 4

def initialize(context):
    set_symbol_lookup_date('2008-3-19')
    secMgr = SecurityManager()
    secMgr.Add(symbol("QQQ"),  1) # QQQ
    secMgr.Add(symbol("DIA"),  1) # DIA
    secMgr.Add(symbol('EEM'),  1) # ISHARES MSCI EMERGING MARKETS
    secMgr.Add(symbol("EFA"),  1) # ISHARES MSCI EAFE ETF
    secMgr.Add(symbol("RSP"),  1) # GUGGENHEIM S&P 500 EQUAL WEIGH
    secMgr.Add(symbol("XLB"),  1) # Materials Select Sector SPDR             
    secMgr.Add(symbol("XLE"),  1) # Energy Select Sector SPDR                
    secMgr.Add(symbol("XLF"),  1) # Financial Select Sector SPDR             
    secMgr.Add(symbol("XLI"),  1) # Industrial Select Sector SPDR            
    secMgr.Add(symbol("XLK"),  1) # Technology Select Sector SPDR            
    secMgr.Add(symbol("XLP"),  1) # Consumer Staples Select Sector SPDR      
    secMgr.Add(symbol("XLU"),  1) # Utilities Select Sector SPDR             
    secMgr.Add(symbol("XLV"),  1) # Healthcare Select Sector SPDR            
    secMgr.Add(symbol("XLY"),  1) # Consumer Discretionary Select Sector SPDR
    secMgr.Add(symbol("VTI"),  1) # VANGUARD TOTAL STOCK MARKET ETF
    secMgr.Add(symbol("VBR"),  1) # VANGUARD SMALL-CAP VALUE ETF
    secMgr.Add(symbol("AGG"),  1) # ISHARES CORE U.S. AGGREGATE BONDS
    
    secMgr.Add(symbol("GS"),   1) # Goldman Sachs
    secMgr.Add(symbol("NKE"),  1) # Nike
    secMgr.Add(symbol("V"),    1) # Visa
    secMgr.Add(symbol("AXP"),  1) # Amex
    secMgr.Add(symbol("BA"),   1) # BOEING CO  
    secMgr.Add(symbol("BAX"),  1) # BAXTER INTERNATIONAL INC  
    secMgr.Add(symbol("CAT"),  1) # CATERPILLAR INC  
    secMgr.Add(symbol("CSCO"), 1) # CISCO SYSTEMS INC  
    secMgr.Add(symbol("CVX"),  1) # CHEVRON CORPORATION  
    secMgr.Add(symbol("DD"),   1) # DU PONT DE NEMOURS E I &CO  
    secMgr.Add(symbol("DIS"),  1) # WALT DISNEY CO-DISNEY COMMON  
    secMgr.Add(symbol("XOM"),  1) # EXXON MOBIL CORPORATION         
    secMgr.Add(symbol("GE"),   1) # GENERAL ELECTRIC CO  
    secMgr.Add(symbol("HD"),   1) # HOME DEPOT INC  
    secMgr.Add(symbol("IBM"),  1) # INTL BUSINESS MACHINES CORP  
    secMgr.Add(symbol("INTC"), 1) # INTEL CORP  
    secMgr.Add(symbol("JNJ"),  1) # JOHNSON AND JOHNSON  
    secMgr.Add(symbol("JPM"),  1) # JPMORGAN CHASE & CO COM STK  
    secMgr.Add(symbol("KO"),   1) # COCA-COLA CO  
    secMgr.Add(symbol("MCD"),  1) # MCDONALDS CORP  
    secMgr.Add(symbol("MMM"),  1) # 3M COMPANY  
    secMgr.Add(symbol("MRK"),  1) # MERCK & CO INC  
    secMgr.Add(symbol("MSFT"), 1) # MICROSOFT CORP  
    secMgr.Add(symbol("PFE"),  1) # PFIZER INC  
    secMgr.Add(symbol("PG"),   1) # PROCTER & GAMBLE CO  
    secMgr.Add(symbol("T"),    1) # AT&T INC. COM  
    secMgr.Add(symbol("TRV"),  1) # Travelers
    secMgr.Add(symbol("UNH"),  1) # UNITEDHEALTH GROUP INC  
    secMgr.Add(symbol("UTX"),  1) # UNITED TECHNOLOGIES CORP  
    secMgr.Add(symbol("VZ"),   1) # VERIZON COMMUNICATIONS  
    secMgr.Add(symbol("WMT"),  1) # WAL-MART STORES INC 
    
    context.SecMgr = secMgr
    context.period = 0
    context.date = None
    
    set_commission(commission.PerTrade(cost=1.0))
    
def handle_data(context, data):
    context.exchange_time = get_datetime().astimezone(pytz.timezone('US/Eastern'))
    if context.exchange_time.date() != context.date: 
        context.date = context.exchange_time.date()
        context.SecMgr.Update(data)    
        context.period += 1
        if (context.period < weightPeriods):
            return
    
        totalWeight = 0
        entries = {}
        exits = {}
        for security in context.SecMgr.GetSecurities():
            if (security.Enabled):
                if (security.Weight - security.Trigger >= .40 and security.Trend > .50):
                    entries[security] = 1.0 - security.Weight
                    totalWeight += 1.0 - security.Weight
                elif (context.portfolio.positions[security.Sid].amount > 0):
                    if (security.Trigger > .50 and security.Trigger < .80):
                        entries[security] = 1.0 - security.Weight
                        totalWeight += 1.0 - security.Weight
                    else:
                        exits[security] = 0
                else:       
                    exits[security] = 0

        if (totalWeight > 0.0):
            #count = float(len(entries))
            for security in entries.keys():
                security.Weight = entries[security] / totalWeight;
                #security.Weight = 1.0 / count
   
        for security in entries.keys():
            order_target_percent(security.Sid, security.Weight)
        for security in exits.keys():
            order_target_percent(security.Sid, 0)
            
        record(Weight=context.SecMgr.GetSecurities()[0].Weight,\
               Trigger=context.SecMgr.GetSecurities()[0].Trigger,\
               Trend=context.SecMgr.GetSecurities()[0].Trend)
   
################################################################                
class SecurityManager(object):
    '''Class to wrap securities'''

    def __init__(self):
        self.stockList = {}

    def __str__(self):
        toString = "\tSymbols:{0}\n".format(self.stockList.keys())
        return toString 
    
    def Count(self):
        return len(self.GetSecurities())
    
    def Add(self, sid, portion):
        self.stockList[sid] = Security(sid, portion)

    def Update(self, data):
        totalWeight = 0.0
        opens=history(bar_count=2, frequency='1d', field= 'open_price')
        highs=history(bar_count=2, frequency='1d', field= 'high')
        lows=history(bar_count=2, frequency='1d', field= 'low')
        closes=history(bar_count=2, frequency='1d', field= 'price')

        for sec in self.stockList.values():
            if sec.Sid not in data:
                sec.Weight = 0.0
                sec.Enabled = False
                continue
            sec.UpdatePrices(opens[sec.Sid][0],highs[sec.Sid][0],lows[sec.Sid][0],closes[sec.Sid][0])
            sec.SetWeight()
            totalWeight += sec.Weight
            sec.Portion = sec.Weight
            
        #if (totalWeight > 0.0):            
        #    for sec in self.stockList.values():
        #        sec.Portion = sec.Weight / totalWeight;
        
        return totalWeight
        
    def GetSecurities(self):
        return self.stockList.values()

   
#################################################################
class Security(object):
    '''Class to wrap security'''

    def __init__(self, sid, portion):
        self.Symbol = sid.symbol
        self.Sid = sid
        self.Portion = portion        
        self.Open = deque(maxlen=trendPeriods)
        self.High = deque(maxlen=trendPeriods)
        self.Low = deque(maxlen=trendPeriods)
        self.Close = deque(maxlen=trendPeriods)
        self.Weight = 0.0
        self.Trigger = 0.0
        self.Trend = 0.0
        self.Enabled = True
            
    def __str__(self):
        toString = "\tSymbol:{0} weight:{1}\n".format(self.Symbol, self.Weight)
        return toString 
    
    def UpdatePrices(self,o,h,l,c):
        self.Open.append(o)
        self.High.append(h)
        self.Low.append(l)
        self.Close.append(c)
            
    def SetWeight(self):
        upPortion = 0
        dnPortion = 0
        span = len(self.Close)
        for i in range(0, span):
            if (self.Close[i] > self.Open[i]):
                upPortion += (i + 1) * (self.High[i] - self.Low[i])
            else:
                dnPortion += (i + 1) * (self.High[i] - self.Low[i])
        if (upPortion + dnPortion > 0):
            factor = upPortion / (upPortion + dnPortion)
            self.Trend = (self.Trend + factor) / 2.0
        
        upPortion = 0
        dnPortion = 0
        if (span > weightPeriods):
            newStart = span - weightPeriods
            for i in range(0, weightPeriods):
                if (self.Close[newStart + i] > self.Open[newStart + i]):
                    upPortion += (i + 1) * (self.High[newStart + i] - self.Low[newStart + i])
                else:
                    dnPortion += (i + 1) * (self.High[newStart + i] - self.Low[newStart + i])
            if (upPortion + dnPortion > 0):
                factor = upPortion / (upPortion + dnPortion)
                self.Weight = factor

        upPortion = 0
        dnPortion = 0
        if (span > triggerPeriods):
            newStart = span - triggerPeriods
            for i in range(0, triggerPeriods):
                if (self.Close[newStart + i] > self.Open[newStart + i]):
                    upPortion += (i + 1) * (self.High[newStart + i] - self.Low[newStart + i])
                else:
                    dnPortion += (i + 1) * (self.High[newStart + i] - self.Low[newStart + i])
            if (upPortion + dnPortion > 0):
                factor = upPortion / (upPortion + dnPortion)
                self.Trigger = factor
        
There was a runtime error.

Why do the results deteriorate in minute mode? We are still only trading once a day, which is very similar to daily trading, right?

On the other hand, even with set_universe, the results still look pretty good (4% alpha), so the strategy is likely viable if we can make the minute mode version track the daily version more closely.

Presumably the edge is dependent on joining the opening auction.

Can't say for sure but there are differences between daily and minutely testing. For one, the slippage model in minutely has much tighter constraints in volume, and the close_price of the first bar is not the day's open. Slippage can cause spreading of an order over several bars resulting in higher uncertainty in the cost basis. This post may be helpful.

Would like to know the simplest way to keep it from going in the hole.

1970-01-01  Starting cash 100000.0  
2003-10-20  New cash low 835.4615  
2003-10-21  New cash low -2133.098  
2004-06-23  New cash low -2150.923  
2004-09-02  New cash low -2416.6681  
2004-09-30  New cash low -3030.1226  
2006-01-27  New cash low -3313.521981  
2007-04-23  New cash low -3799.721181  
2007-09-27  New cash low -5850.262881  
2009-04-08  New cash low -6899.456317  
2009-04-22  New cash low -10969.950317  
2009-06-11  New cash low -18195.840017  
End of logs.  
Clone Algorithm
25
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
# -*- coding: utf-8 -*-  
"""

quantshim dev scratch.  Licensed under GPL3
written by [email protected]


"""



# Import the libraries we will use here
import datetime
import pytz
import math
import numpy
import pandas
import scipy
import scipy.stats
import zipline
import functools
import collections

import sklearn
import sklearn.naive_bayes
#import sklearn.naive_bayes.BernoulliNB
import sklearn.linear_model
import sklearn.ensemble

import talib




is_offline_Zipline = False

#quantopian shims
class WorstSpreadSlippage(slippage.SlippageModel):
    '''will trade at the worst value of the order minute.  high if long, low if short. 
    additionally, supports 'VolumeShareSlippage' functionality, which further biases price/volume'''
    def __init__(this, volume_limit=.25, price_impact=0.1, ohlcWeighted=False):
        this.volume_limit = volume_limit
        this.price_impact = price_impact
        this.ohlcWeighted = ohlcWeighted
        pass
    def __processVolumeShareSlippage(self,event,order, targetPrice):
        '''coppied implementation from VolumeShareSlippage.process_order(), found here: https://github.com/quantopian/zipline/blob/4860a966b3a3102fa80d43f393155e53015cc349/zipline/finance/slippage.py
        modification:  we return the final (price,volume) tuple for our main .process_order() to use, instead of executing the order
        RETURNS: final (price,volume) tuple'''
        ########
        max_volume = self.volume_limit * event.volume

        # price impact accounts for the total volume of transactions
        # created against the current minute bar
        remaining_volume = max_volume - self.volume_for_bar
        if remaining_volume < 1:
            # we can't fill any more transactions
            return (0.0,0)
        # the current order amount will be the min of the
        # volume available in the bar or the open amount.
        cur_volume = int(min(remaining_volume, abs(order.open_amount)))

        if cur_volume < 1:
            return (0.0,0)

        # tally the current amount into our total amount ordered.
        # total amount will be used to calculate price impact
        total_volume = self.volume_for_bar + cur_volume

        volume_share = min(total_volume / event.volume,
                           self.volume_limit)

        simulated_impact = volume_share ** 2 \
            * math.copysign(self.price_impact, order.direction) \
            * targetPrice
        #return create_transaction(
        #    event,
        #    order,
        #    # In the future, we may want to change the next line
        #    # for limit pricing
        #    event.price + simulated_impact,
        #    math.copysign(cur_volume, order.direction)
        return (targetPrice + simulated_impact,int(math.copysign(cur_volume, order.direction)))

    def process_order(this,trade_bar,order):
        
        #worst spread
        if order.amount < 0:
            targetPrice = trade_bar.low
        else:
            targetPrice = trade_bar.high
        #trade at the open
        #targetPrice = trade_bar.open_price

        if this.ohlcWeighted:
            #midpoint, ohlc weighted
            targetPrice = (targetPrice + trade_bar.open_price + trade_bar.high + trade_bar.low + trade_bar.close_price) / 5
            pass


        price, volume = this.__processVolumeShareSlippage(trade_bar,order,targetPrice)
        priceSlippage = trade_bar.close_price - price   
        volumeSlippage = order.amount - volume    

        if price == 0.0 or volume == 0:
            return

        #logger.info(price)
        logger.info("ORDER_COMMITTED: {0} shares {1} @ {2} \n\t  v={8} o={4} h={5} l={6} c={7} \t (WorstSpreadSlippage: vol= -{9} price= {3:.2f})"
                    .format(volume,trade_bar.sid.symbol,price,priceSlippage, trade_bar.open_price, trade_bar.high, trade_bar.low, trade_bar.close_price, trade_bar.volume,volumeSlippage))
        
        return slippage.create_transaction(trade_bar,
                                            order,
                                            price,
                                            order.amount)

class TradeAtTheOpenSlippageModel_Simple(slippage.SlippageModel):
    def __init__(self, fractionOfOpenCloseRange):
        self.fractionOfOpenCloseRange = fractionOfOpenCloseRange

    def process_order(self, trade_bar, order):
        openPrice = trade_bar.open_price
        closePrice = trade_bar.price
        ocRange = closePrice - openPrice
        ocRange = ocRange * self.fractionOfOpenCloseRange
        targetExecutionPrice = openPrice + ocRange
            
        # Create the transaction using the new price we've calculated.
        return slippage.create_transaction(
            trade_bar,
            order,
            targetExecutionPrice,
            order.amount
        )
        
class TradeAtTheOpenSlippage(slippage.SlippageModel):
    '''will trade at the open, good for daily use, kind of not good otherwise.'''
    def __init__(this, volume_limit=.25, price_impact=0.1):
        this.volume_limit = volume_limit
        this.price_impact = price_impact
        pass
    def __processVolumeShareSlippage(self,event,order, targetPrice):
        '''coppied implementation from VolumeShareSlippage.process_order(), found here: https://github.com/quantopian/zipline/blob/4860a966b3a3102fa80d43f393155e53015cc349/zipline/finance/slippage.py
        modification:  we return the final (price,volume) tuple for our main .process_order() to use, instead of executing the order
        RETURNS: final (price,volume) tuple'''
        ########
        max_volume = self.volume_limit * event.volume

        # price impact accounts for the total volume of transactions
        # created against the current minute bar
        remaining_volume = max_volume - self.volume_for_bar
        if remaining_volume < 1:
            # we can't fill any more transactions
            return (0.0,0)
        # the current order amount will be the min of the
        # volume available in the bar or the open amount.
        cur_volume = int(min(remaining_volume, abs(order.open_amount)))

        if cur_volume < 1:
            return (0.0,0)

        # tally the current amount into our total amount ordered.
        # total amount will be used to calculate price impact
        total_volume = self.volume_for_bar + cur_volume

        volume_share = min(total_volume / event.volume,
                           self.volume_limit)

        simulated_impact = volume_share ** 2 \
            * math.copysign(self.price_impact, order.direction) \
            * targetPrice
        #return create_transaction(
        #    event,
        #    order,
        #    # In the future, we may want to change the next line
        #    # for limit pricing
        #    event.price + simulated_impact,
        #    math.copysign(cur_volume, order.direction)
        return (targetPrice + simulated_impact,int(math.copysign(cur_volume, order.direction)))

    def process_order(this,trade_bar,order):
        
        
        #if order.amount < 0:
        #    targetPrice = trade_bar.low
        #else:
        #    targetPrice = trade_bar.high
        targetPrice = trade_bar.open_price

        price, volume = this.__processVolumeShareSlippage(trade_bar,order,targetPrice)
        priceSlippage = trade_bar.close_price - price   
        volumeSlippage = order.amount - volume    

        if price == 0.0 or volume == 0:
            return

        #logger.info(price)
        logger.info("ORDER_COMMITTED: {0} shares {1} @ {2} \n\t  v={8} o={4} h={5} l={6} c={7} \t (TradeAtTheOpenSlippage: vol= -{9} price= {3:.2f})"
                    .format(volume,trade_bar.sid.symbol,price,priceSlippage, trade_bar.open_price, trade_bar.high, trade_bar.low, trade_bar.close_price, trade_bar.volume,volumeSlippage))
        
        return slippage.create_transaction(trade_bar,
                                            order,
                                            price,
                                            order.amount)

    
class CustomSlippage(slippage.SlippageModel):
    ''' allows customizing slippage if desired, though mostly used for logging your order details to the console'''
    def __init__(this, volume_limit=.25, price_impact=0.1, ohlcWeighted=False):
        this.volume_limit = volume_limit
        this.price_impact = price_impact
        this.ohlcWeighted = ohlcWeighted
        pass
    def __processVolumeShareSlippage(self,event,order, targetPrice):
        '''coppied implementation from VolumeShareSlippage.process_order(), found here: https://github.com/quantopian/zipline/blob/4860a966b3a3102fa80d43f393155e53015cc349/zipline/finance/slippage.py
        modification:  we return the final (price,volume) tuple for our main .process_order() to use, instead of executing the order
        RETURNS: final (price,volume) tuple'''
        ########
        max_volume = self.volume_limit * event.volume

        # price impact accounts for the total volume of transactions
        # created against the current minute bar
        remaining_volume = max_volume - self.volume_for_bar
        if remaining_volume < 1:
            # we can't fill any more transactions
            return (0.0,0)
        # the current order amount will be the min of the
        # volume available in the bar or the open amount.
        cur_volume = int(min(remaining_volume, abs(order.open_amount)))

        if cur_volume < 1:
            return (0.0,0)

        # tally the current amount into our total amount ordered.
        # total amount will be used to calculate price impact
        total_volume = self.volume_for_bar + cur_volume

        volume_share = min(total_volume / event.volume,
                           self.volume_limit)

        simulated_impact = volume_share ** 2 * math.copysign(self.price_impact, order.direction) * targetPrice
        #return create_transaction(
        #    event,
        #    order,
        #    # In the future, we may want to change the next line
        #    # for limit pricing
        #    event.price + simulated_impact,
        #    math.copysign(cur_volume, order.direction)
        return (targetPrice + simulated_impact,int(math.copysign(cur_volume, order.direction)))

    def process_order(this,trade_bar,order):
        
        ####worst spread
        #if order.amount < 0:
        #    targetPrice = trade_bar.low
        #else:
        #    targetPrice = trade_bar.high
        ####trade at the open
        #targetPrice = trade_bar.open_price
        ####trade at the close
        targetPrice = trade_bar.close_price

        if this.ohlcWeighted:
            #midpoint, ohlc weighted
            targetPrice = (targetPrice + trade_bar.open_price + trade_bar.high + trade_bar.low + trade_bar.close_price) / 5
            pass


        price, volume = this.__processVolumeShareSlippage(trade_bar,order,targetPrice)
        priceSlippage = trade_bar.close_price - price   
        volumeSlippage = order.amount - volume    

        if price == 0.0 or volume == 0:
            return
        
        
        #construct our pnl once this transaction is comitted (logged below)
        pnl = _g.context.portfolio.pnl + (price * order.amount) - (trade_bar.close_price * order.amount)

        #logger.info(price)
        logger.info("ORDER_COMMITTED: {0} shares {1} @ {2} \n\t  v={8} o={4} h={5} l={6} c={7} \t (Slippage: vol= -{9} price= {3:.2f})\n\tpnl={10}"
                    .format(volume,trade_bar.sid.symbol,price,priceSlippage, trade_bar.open_price, trade_bar.high, trade_bar.low, trade_bar.close_price, trade_bar.volume,volumeSlippage, pnl))
        
        return slippage.create_transaction(trade_bar,
                                            order,
                                            price,
                                            order.amount)

class Logger():
    '''shim for exposing the same logging definitions to visualstudio intelisence'''
    def __init__(this, logErrors=True, logInfos=True, logWarns=True, logDebugs=True):        
        this.__logErrors = logErrors
        this.__logInfos = logInfos
        this.__logWarns = logWarns
        this.__logDebugs = logDebugs
        this.__recordHistory = {}
        this.__lastKnownDay = None
        pass    

    def error(this, message): 
        if not this.__logErrors: return  
        log.error(this.__wrapMessage(message))
        pass
    def info(this, message):
        if not this.__logInfos: return  
        #log.info(this.__wrapMessage(message))
        pass
    def warn(this, message):   
        if not this.__logWarns: return  
        log.warn(this.__wrapMessage(message))
        pass
    def debug(this, message):  
        if not this.__logDebugs: return  
        log.debug(this.__wrapMessage(message))
        pass

    def __wrapMessage(this,message):
        this.__trySpamDailyLogs() 
        timestamp = _g.context.framework._getDatetime()
        
        #return str(timestamp) + message
        time = timestamp.strftime("%H:%M")
        
        #if timestamp.second!=0:
        #    time += ":{0}".format(timestamp.second)

        return str(time) + ": " + str(message)
        pass

    def debugAccumulateDaily(this,key,message):
        '''writes the log once a day to avoid spam.  includes timestamp automatically'''
        if not this.__logDebugs: return  
        msg = this.__wrapMessage(message)
        this.__storeToDailyLog(key,msg)

    def debugOnceDaily(this,key,message):
        if not this.__logDebugs: return  
        
        this.__storeToDailyLog(key,message)
        this.__recordHistory[key] = this.__recordHistory[key][0:1]
        this.__trySpamDailyLogs()
        pass
    def __storeToDailyLog(this,key,message):
        if not this.__recordHistory.has_key(key):
            this.__recordHistory[key] = []
        this.__recordHistory[key].append(message)

        pass

    def __trySpamDailyLogs(this):
        if _g.context.framework.thisFrameDay != this.__lastKnownDay:
            #new day, dump our previous logs
            this.__lastKnownDay = _g.context.framework.thisFrameDay   
            for key,values in this.__recordHistory.items():                         
                this.debug("[email protected]{0}=\n{1}".format(key,",".join(values)))
                values[:] = [] #clear it
        pass

    def record(this, name,value, logDaily=False):                    
        this.__trySpamDailyLogs()            
        if(logDaily == True):
            this.__storeToDailyLog(name,"%0.4f" % value)
        record(**{name:value})

    def recordNormalized(this, name,value,baseline=1,subtract=0, logDaily=False):    
        '''normalize values to a 0 to 1 range'''

        if value - subtract == 0 or baseline == 0:
            toRecord = 0
        else:
            toRecord = (value - subtract) / baseline

        this.record(name,toRecord,logDaily=logDaily)

    #def getLastRecord(this,name):
    #    '''returns the last recorded value.  only exists if doing daily
    #    outputs, and during the day.  returns None if name not found'''
    #    return this.__recordHistory.get(name)
    pass

global logger
logger = Logger() #(logDebugs=False)

class Shims():
    '''SHIM OF QUANTOPIAN INTERNAL REPRESENTATION.  here for intelisence only.  you SHOULD NOT actually instantiate these.'''
    
    class Position:
        '''
        The position object represents a current open position, and is contained inside the positions dictionary. 
        For example, if you had an open AAPL position, you'd access it using context.portfolio.positions[sid(24)]. 
        The position object has the following properties:
            amount = 0 #Integer: Whole number of shares in this position.
            cost_basis = 0.0 #Float: The volume-weighted average price paid per share in this position.
            last_sale_price = 0.0 #Float: Price at last sale of this security.
            sid = 0 #Integer: The ID of the security.
        '''
        def __init__(this):
            this.amount = 0 #Integer: Whole number of shares in this position.
            this.cost_basis = 0.0 #Float: The volume-weighted average price paid per share in this position.
            this.last_sale_price = 0.0 #Float: Price at last sale of this security.
            this.sid = 0 #Integer: The ID of the security.

    class Context():
        def __init__(this , portfolio=zipline.protocol.Portfolio()): #, tradingAlgorithm = zipline.TradingAlgorithm()):
            this.portfolio = portfolio
            #this.tradingAlgorithm = tradingAlgorithm
            pass
        pass

    


    

    class _TradingAlgorithm_QuantopianShim:
        '''shim of zipline.TradingAlgorithm for use on quantopian '''
        def __init__(this):
            #this.logger = Shims._Logger()
            #this.logger = log
            pass
        

        def order(this,sid,amount,limit_price=None, stop_price=None):
            '''
            Places an order for the specified security of the specified number of shares. Order type is inferred from the parameters used. If only sid and amount are used as parameters, the order is placed as a market order.
            Parameters
            sid: A security object.
            amount: The integer amount of shares. Positive means buy, negative means sell.
            limit_price: (optional) The price at which the limit order becomes active. If used with stop_price, the price where the limit order becomes active after stop_price is reached.
            stop_price: (optional) The price at which the order converts to a market order. If used with limit_price, the price where the order converts to a limit order.
            Returns
            An order id.
            '''
            if sid is Security:
                security = sid
            else:
                security = this.context.framework.allSecurities[sid]
            #logger.info("{0} ordering {1}".format(security.qsec,amount))
            orderId = order(security.qsec,amount,limit_price,stop_price)
            return orderId
            pass

        def order_percent(self, sid, percent, limit_price=None, stop_price=None):
            """
            Place an order in the specified security corresponding to the given
            percent of the current portfolio value.

            Note that percent must expressed as a decimal (0.50 means 50\%).
            """
            value = self.context.portfolio.portfolio_value * percent
            return self.order_value(sid, value, limit_price, stop_price)

        def order_target(self, sid, target, limit_price=None, stop_price=None):
            """
            Place an order to adjust a position to a target number of shares. If
            the position doesn't already exist, this is equivalent to placing a new
            order. If the position does exist, this is equivalent to placing an
            order for the difference between the target number of shares and the
            current number of shares.
            """
            if sid in self.context.portfolio.positions:
                current_position = self.context.portfolio.positions[sid].amount
                req_shares = target - current_position
                return self.order(sid, req_shares, limit_price, stop_price)
            else:
                return self.order(sid, target, limit_price, stop_price)

        def order_target_value(self, sid, target, limit_price=None,
                               stop_price=None):
            """
            Place an order to adjust a position to a target value. If
            the position doesn't already exist, this is equivalent to placing a new
            order. If the position does exist, this is equivalent to placing an
            order for the difference between the target value and the
            current value.
            """
            if sid in self.context.portfolio.positions:
                current_position = self.context.portfolio.positions[sid].amount
                current_price = self.context.portfolio.positions[sid].last_sale_price
                current_value = current_position * current_price
                req_value = target - current_value
                return self.order_value(sid, req_value, limit_price, stop_price)
            else:
                return self.order_value(sid, target, limit_price, stop_price)

        def order_target_percent(self, sid, target, limit_price=None,
                                 stop_price=None):
            """
            Place an order to adjust a position to a target percent of the
            current portfolio value. If the position doesn't already exist, this is
            equivalent to placing a new order. If the position does exist, this is
            equivalent to placing an order for the difference between the target
            percent and the current percent.

            Note that target must expressed as a decimal (0.50 means 50\%).
            """
            if sid in self.context.portfolio.positions:
                current_position = self.context.portfolio.positions[sid].amount
                current_price = self.context.portfolio.positions[sid].last_sale_price
                current_value = current_position * current_price
            else:
                current_value = 0
            target_value = self.context.portfolio.portfolio_value * target

            req_value = target_value - current_value
            return self.order_value(sid, req_value, limit_price, stop_price)

        pass

    #class _TradingAlgorithm_ZiplineShim(zipline.TradingAlgorithm):
    #    '''auto-generates a context to use'''
    #    def initialize(this):
    #        #delay initialize until start of first handle-data, so our
    #        #portfolio object is available
    #        #this.__isInitialized = False;
    #        this.context = Shims.Context()
    #        this.context.tradingAlgorithm = this            
    #        #this.context.portfolio = this.portfolio
    #        pass

    #    def handle_data(this,data):      
    #        this.context.portfolio = this.portfolio
    #        #if not this.__isInitialized:
    #        #    this.__isInitialized=True
    #        #    this.context.portfolio=this.portfolio
                
    #        this.context.framework._update(data)
    #        pass
    #    pass

class FrameHistory:
    def __init__(this,parent,framework, data):
        this.parent = parent
        this.framework = framework
        this.state = []
        this.isActive = this.parent.isActive
        #this.maxHistoryFrames = this.framework.maxHistoryFrames
        #assert(this.framework.simFrame == this.parent.simFrame, "parent frame
        #does not match")
        
        this.initialize(data)
    
    def initialize(this, data):
        '''overridable'''
        logger.error("FrameHistory.initialize() invoked.  You should override this method.")
        pass

    def constructFrameState(this,data):
        '''override and return the frame state, this will be prepended to history
        if you return NONE, the frame state (history) is not modified.'''   
        logger.error("FrameHistory.constructFrameState() invoked.  You should override this method.")             
        pass

    def _update(this,data):
        this.isActive = this.parent.isActive
        if not this.isActive:
            return

        

        currentState = this.constructFrameState(data)
        if(currentState != None):
            currentState.datetime = this.framework._getDatetime()
            currentState.simFrame = this.framework.simFrame

            this.state.insert(0,currentState)
            del this.state[this.framework.maxHistoryFrames:]

class StrategyPosition:
    '''allows two or more stratgies to controll their own positions (orders) for securities they care about, 
    without interfering with the orders of other strategies.

    To use:   each strategy should set security.myStrategyPositon.targetCapitalSharePercent, which is a percentage of your entire portfolio's value
    then execute the order (and/or rebalance) by invoking security.myStrategyPosition.processOrder()
    '''

    def __init__(this, security, strategyName):            
        this._security = security
        this._strategyName = strategyName
        this._lastOrderId = 0
        this._lastStopOrderId = 0
        this._currentCapitalSharePercent = 0.0
        this._currentShares = 0
        #for the last trade roundtrip, the aproximate returns.  set every time our percent changes to zero
        this._lastRoundtripReturns = 0.0
        #this is editable
        this.targetCapitalSharePercent = 0.0
        #price when we decided to order, not actually the fulfillment price
        this.__lastOrderPrice = 0.0
        this.__currentPeakGains = 0.0
        this.__currentPeakGainsDecay = 0.0
        this._currentReturns = 0.0 #returns of current open position. 
        this._totalTrades = 0 #total trades we execute via this strategyPosition.  note that due to partial fills, this may be less than actual trades

    def processOrder(this, data, rebalanceThreshholdPercent=0.05, maxLosses=None, maxGainsAdditionalDrawdown=None, maxGainsDecay=0.01): #, OBSOLETE_stopLimitPercent=0.0, OBSOLETE_momentumStopLimit = True, OBSOLETE_decayMomentum = 0.001):
        ''' set rebalanceThreshholdPercent to zero (0.0) to cause the position to readjust even if the targetPercentage doesn't change.   this is useful for reinvesting divideds / etc
        but is set to 0.05 (5 percent) so we don't spam orders 
        
        maxLosses:  close if our open position suffers a loss of this percent or more
        maxGainsAdditionalDrawdown : close if our open position's gains suffer a decrease of this+maxLosses or more.
        maxGainsDecay : over time this will reduce the acceptable gains drawdown (specified by maxGainsAdditionalDrawdown) so that on long-running gains we don't incur such a large drawdown before closing.
        '''
        #if momentumStopLimit == True (the default) we will stopLimitPercent based on the peak gains, not based on the original purchase price (this is generally a good ideas as it will maximize your gains)
        #decayMomentum : = if == 0.01 and using momentumStopLimit==True, we will decay the position's survival chances by 1% per tick until it's finally closed.
        
        if this._currentCapitalSharePercent == 0.0 and this.targetCapitalSharePercent == 0.0:
            #no work to do
            return 0



        currentPrice = data[this._security.qsec].close_price
        
        if this._currentCapitalSharePercent == this.targetCapitalSharePercent and this._currentCapitalSharePercent != 0.0:
            #update current returns
            this._currentReturns = (currentPrice - this.__lastOrderPrice) / this.__lastOrderPrice * math.copysign(1.0,this._currentCapitalSharePercent)
        else:
            #target is different so reset our returns as we are about to change our order
            this._currentReturns = 0.0


        if this._currentCapitalSharePercent == this.targetCapitalSharePercent and maxGainsAdditionalDrawdown != None:
            ##handle maxGains stoplimits
            gainsPercent = this._currentReturns - this.__currentPeakGainsDecay
            #if gainsPercent < -maxLosses:
            #    #loosing, so close out
            #    logger.debug("loosing, so close out.  gainsPercent={0}, maxLosses={1}".format(gainsPercent, maxLosses))
            #    this.targetCapitalSharePercent = 0.0 
            #else:

            if this._currentReturns > this.__currentPeakGains:
                this.__currentPeakGains = this._currentReturns
                this.__currentPeakGainsDecay = 0.0 #reset decay 
            else:
                #need to see if our gain exceed our stoplimitGains threshhold
                gainsFloorThreshhold = this.__currentPeakGains * maxGainsAdditionalDrawdown
                if gainsPercent < gainsFloorThreshhold:
                    lossesFromPeak = this.__currentPeakGains - gainsPercent
                    if maxLosses != None and lossesFromPeak < maxLosses:
                        #we are not yet exceeding maxLosses (from our peak) so don't close out yet
                        logger.debug("we are not yet exceeding maxLosses (from our peak) so don't close out yet.  \t {0} @ {1}, gains={2}".format(this._security.symbol,currentPrice,this._currentReturns))
                        pass
                    else:
                        #loosing from our peak, so close out
                        logger.debug("loosing from our peak, so close out.  gainsPercent={0:.4f}, \t gainsFloorThreshhold={1:.4f}, \t  lossesFromPeak={2:.4f}, \t  maxLosses={3:.4f}  \t this._currentReturns={4:.4f}".format(gainsPercent, gainsFloorThreshhold, lossesFromPeak, maxLosses,this._currentReturns))
                        this.targetCapitalSharePercent = 0.0 

                this.__currentPeakGainsDecay += (this.__currentPeakGains * maxGainsDecay)
        else:
            this.__currentPeakGains = 0.0
            this.__currentPeakGainsDecay = 0.0

        if this._currentCapitalSharePercent == this.targetCapitalSharePercent and this._currentCapitalSharePercent != 0.0:
            #handle maxlosses stoplimit
            if maxLosses != None and this._currentReturns < -maxLosses:
                logger.debug("maxlosses stoplimit.  this._currentReturns={0}, maxLosses={1}".format(this._currentReturns, maxLosses))
                this.targetCapitalSharePercent = 0.0


           

        if this.targetCapitalSharePercent == 0.0 and this._currentCapitalSharePercent != 0.0:
            #record our expected PnL
            this._lastRoundtripReturns = this._currentReturns

        this._currentCapitalSharePercent = this.targetCapitalSharePercent
        
        
           
        #determine value of percent
        targetSharesValue = this._security.framework.context.portfolio.portfolio_value * this._currentCapitalSharePercent
        targetSharesTotal = int(math.copysign(math.floor(abs(targetSharesValue / currentPrice)),targetSharesValue))
        
        targetSharesDelta = targetSharesTotal - this._currentShares

        if targetSharesTotal != 0:
            if abs(targetSharesDelta / (targetSharesTotal * 1.0)) < rebalanceThreshholdPercent:
                #logger.debug("{0} ORDER SKIPPED! {1} (change to small) : {2} + {3} => {4} shares".format(this.strategyName,this.security.symbol, this.currentShares, targetSharesDelta, targetSharesTotal))          
                #our position change was too small so we skip rebalancing
                return

        #do actual order
        if(abs(targetSharesDelta) >= 1): #can not perform an order on less than 1 share
            ####cancel previous open order, if any  #doesn't really work, as even when canceling, some shares may be filled so you'll be left in an uncomplete state
            ###lastOrder = get_order(this.lastOrderId)
            ###unfilled = lastOrder.amount - l
            ###cancel_order(this.lastOrderId)
            logger.info("{0} order {1} : {2} + {3} => {4} shares  \t \t decisionPrice={5} ".format(this._strategyName,this._security.symbol, this._currentShares, targetSharesDelta, targetSharesTotal,currentPrice))          
            this._lastOrderId = this._security.framework.tradingAlgorithm.order(this._security.sid,targetSharesDelta,None,None)
            this._currentShares = targetSharesTotal
            this.__lastOrderPrice = currentPrice
            this._totalTrades += 1
            this._security.framework._totalTrades += 1
            
            return this._lastOrderId
        else:
            return 0

class Security:
    isDebug = False


    class QSecurity:
        '''
        Quantopian internal security object
        If you have a reference to a security object, there are several properties that might be useful:
            sid = 0 #Integer: The id of this security.
            symbol = "" #String: The ticker symbol of this security.
            security_name = "" #String: The full name of this security.
            security_start_date = datetime.datetime() #Datetime: The date when this security first started trading.
            security_end_date = datetime.datetime() #Datetime: The date when this security stopped trading (= yesterday for securities that are trading normally, because that's the last day for which we have historical price data).
        '''
        def __init__(this):
            this.sid = 0 #Integer: The id of this security.
            this.symbol = "" #String: The ticker symbol of this security.
            this.security_name = "" #String: The full name of this security.
            this.security_start_date = datetime.datetime(1990,1,1) #Datetime: The date when this security first started trading.
            this.security_end_date = datetime.datetime(1990,1,1) #Datetime: The date when this security stopped trading (= yesterday for securities that are trading normally, because that's the last day for which we have historical price data).
    
    

    def __init__(this,sid, framework):
        this.sid = sid  
        this.isActive = False
        this.framework = framework
        this.security_start_date = datetime.datetime.utcfromtimestamp(0)
        this.security_end_date = datetime.datetime.utcfromtimestamp(0)
        this.simFrame = -1
        this.security_start_price = 0.0
        this.security_end_price = 0.0
        #this.daily_open_price = [0.0]
        #this.daily_close_price = [0.0]
        this.symbol = "??? Not yet active so symbol not known"
        
        
    def getCurrentPosition(this):
        if this.simFrame == -1:
            return Shims.Position()
        return this.framework.context.portfolio.positions[this.qsec]

    def update(this,qsec, data):
        '''qsec is only given when it's in scope, and it can actually change each timestep 
        what it does:
        - construct new state for this frame
        - update qsec to most recent (if any)
        '''
        #update our tickcounter, mostly for debug
        this.simFrame = this.framework.simFrame
        #assert(this.simFrame >= 0,"security.update() frame not set")

        
        
        #update qsec to most recent (if any) 67
        this.qsec = qsec
        if qsec:
            this.isActive = True
            this.symbol = qsec.symbol
            #assert(qsec.sid == this.sid,"security.update() sids do not match")
            
            if this.security_start_price == 0.0:
                this.security_start_price = data[this.sid].close_price
            this.security_end_price = data[this.sid].close_price

            this.security_start_date = qsec.security_start_date
            this.security_end_date = qsec.security_end_date
        else:
            this.isActive = False

        #try:
        #    this.daily_close_price =
        #    this.framework.daily_close_price[this.qsec]
        #    this.daily_open_price = this.framework.daily_open_price[this.qsec]
        #except:
        #    this.daily_close_price = []
        #    this.daily_open_price = []

        #if len(this.daily_close_price) == 0 or len(this.daily_open_price) ==
        #0:
        #    this.isActive = False
class FrameworkBase():
    def __init__(this, context, data, maxHistoryFrames=60): #5 days of history
        this.maxHistoryFrames = maxHistoryFrames
        this.__isFirstTimestepRun = False
        this.context = context
        this.tradingAlgorithm = Shims._TradingAlgorithm_QuantopianShim() #prepopulate to allow intelisence
        this.tradingAlgorithm = context.tradingAlgorithm
        this.simFrame = -1 #the current timestep of the simulation
        this.framesToday = -1 #number of frames executed today
        
        this.allSecurities = {} #dictionary of all securities, including those not targeted
        
        this.activeSecurities = {}

        #stub for intelisence propigation
        this.allSecurities["1"]=Security(0,this)
        this.allSecurities.clear()


        this.thisFrameDay = 0
        this.lastFrameDay = 0

        this._totalTrades = 0 #total trades we execute via all strategyPositions.  note that due to partial fills, this may be less than actual trades

        this.isIntradayRunDetected = False #if we are running in intraday, this will be set to true on frame 2.  the 2nd bar will be in the same day as the first bar.  no better way to detect unfortunately.

        #for storing quantopian history
        #this.daily_close_price = pandas.DataFrame()
        #this.daily_open_price = pandas.DataFrame()
        
        this._initialize(data)

        pass
    def ensureMinHistory(this, minFrames):
        '''increases the history frames if the current is less than your required min.  
        this is a good way to set your history, as too much history will slow down your sim, and can crash it due to out-of-memory'''

        if this.maxHistoryFrames < minFrames:
            this.maxHistoryFrames = minFrames      
    
    def _initialize(this, data):
        '''starts initialiation of the framework
        do not override this, or any other method starting with an underscore.
        methods without an underscore prefix can and should be overridden.'''
        #do init here
        this.initialize(data)        
        pass

    def initialize(this, data):
        '''override this to do your init'''
        logger.error("You should override FrameworkBase.initialize()")
        pass


    def initializeFirstUpdate(this,data):
        '''override this.  called the first timestep, before update.  
        provides access to the 'data' object which normal .initialize() does not'''
        logger.error("You should override FrameworkBase.initializeFirstUpdate()")
        pass

    def _update(this,data):

        '''invoked by the tradingAlgorithm shim every update.  internally we will call abstract_update_timestep_handle_data()
        DO NOT OVERRIDE THIS OR ANY METHODS STARTING WITH AN UNDERSCORE
        override methods without underscores.
        '''
        
        #frame updates
        #this.data = data

        this.simFrame+=1        
        
        this.lastFrameDay = this.thisFrameDay
        this.thisFrameDay = this._getDatetime().day

        
        #supdating our history once per day
        if(this.thisFrameDay != this.lastFrameDay):
            #only update this once per day, hopefully improving performance...
            #this.daily_close_price = history(bar_count=180, frequency='1d',
            #field='close_price')
            #this.daily_open_price = history(bar_count=180, frequency='1d',
            #field='open_price')
            this.framesToday = 0
        else:
            this.framesToday += 1
            this.isIntradayRunDetected = True

        this.__updateSecurities(data)
        

        if not this.__isFirstTimestepRun:
            this.__isFirstTimestepRun = True
            this.initializeFirstUpdate(data)

        this.update(data)
        pass

    def update(this,data):
        '''override and update your usercode here'''
        logger.error("You should override FrameworkBase.update()")
        pass

    def __updateSecurities(this,data):
        '''get all qsecs from data, then update the targetedSecurities accordingly'''
        #logger.debug("FrameworkBase.__updateSecurities() start.
        #allSecLength={0}".format(len(this.allSecurities)))
        #convert our data into a dictionary
        currentQSecs = {}
        newQSecs = {}
        for qsec in data:            
            #if online, qsec is a securities object
            sid = qsec.sid      
            
            #logger.debug("FrameworkBase.__updateSecurities() first loop, found
            #{0}, sid={1}.  exists={2}".format(qsec,
            #sid,this.allSecurities.has_key(sid) ))

            currentQSecs[sid] = qsec
            #determine new securities found in data
            if not this.allSecurities.has_key(sid):
                logger.debug("FrameworkBase.__updateSecurities() new security detected.  will construct our security object for it: {0}".format(qsec))
                newQSecs[sid] = qsec


        #construct new Security objects for our newQSecs
        for sid, qsec in newQSecs.items():            
            #assert(not
            #this.allSecurities.has_key(sid),"frameworkBase.updateSecurities
            #key does not exist")
            #logger.debug("FrameworkBase.__updateSecurities() new security
            #found {0}".format(qsec))
            security = this._getOrCreateSecurity(qsec, data)
            this.allSecurities[security.sid] = security

        newQSecs.clear()

        #update all security objects, giving a null qsec if one doesn't exist
        #in our data dictionary
        for sid, security1 in this.allSecurities.items():
            qsec = currentQSecs.get(sid)
            security1.update(qsec, data)

        ## determine active securities set.
        this.activeSecurities.clear()
        for sid,security2 in this.allSecurities.items():
            if not security2.isActive:
                #logger.debug("FrameworkBase.__updateSecurities() NOT ACTIVE
                #{0}".format(security.qsec))
                continue
            #logger.debug("FrameworkBase.__updateSecurities() ACTIVE
            #{0}".format(security.qsec))
            this.activeSecurities[sid] = security2
            pass

        pass

    def initializeSecurity(this,security, data):
        '''override to do custom init logic on each security. 
        if you wish to use your own security, return it (it will replace the existing)'''
        logger.error("You should override FrameworkBase.initializeSecurity()")
        pass       
             
    def _getOrCreateSecurities(this,qsecArray, data):
        '''pass in an array of quantopian sid/sec tuples  (ex:  [(24,sid(24)),(3113,sid(3113))]) 
        and returns an array of unique security objects wrapping them.   duplicate sids are ignored'''

        securities = {}

        for qsec in qsecArray:            
            security = this._getOrCreateSecurity(qsec, data)
            securities[security.sid] = security
            pass

        return securities.values()

    def _getOrCreateSecurity(this, qsec, data):
        '''pass in a quantopian sec (ex:  sid(24)) and returns our security object wrapping it
        if the security object
        '''
        
        sid = qsec.sid
        if this.allSecurities.has_key(sid):
            return this.allSecurities[sid]

        #does not exist, have to create
        newSecurity = Security(sid,this)
        #new, so do our framework's custom init logic on this security
        maybeNewSec = this.initializeSecurity(newSecurity, data)
        if maybeNewSec is not None:
            #framework replaced newSec with a different sec
            newSecurity = maybeNewSec
                
        this.allSecurities[sid] = newSecurity
        
        return newSecurity
        pass


    def _getDatetime(this):
        '''returns current market time, using US/Eastern timezone'''
        return pandas.Timestamp(pandas.Timestamp(get_datetime()).tz_convert('US/Eastern'))
#entrypoints

def handle_data(context=Shims.Context(),data=pandas.DataFrame()):   
    '''update method run every timestep on quantopian'''
    
    cash = context.portfolio.cash
    if cash < context.cash_low:
        print 'New cash low ' + str(cash)
        context.cash_low = cash
    
    
    #try:
    if context.firstFrame:
        #'''init on our first frame'''
        context.firstFrame = False
        context.tradingAlgorithm = Shims._TradingAlgorithm_QuantopianShim()
        context.tradingAlgorithm.context = context
        context.framework = constructFramework(context,data)
        
    
    context.framework._update(data)
    #except Exception,e:
    #    print "Caught:",e

    pass

class Global():
    pass
global _g
_g = Global()




def initialize(context=Shims.Context()):
    '''initialize method used when running on quantopian'''
    context.firstFrame = True 
    
    context.cash_low = context.portfolio.cash
    print 'Starting cash ' + str(context.cash_low)
    
    _g.context = context
    #context.spy = sid(8554) #SPY
    ########## SET UNIVERSE
    #if you need set universe, do it here (note that doing this slows the algo
    #considerably)
    #set_universe(universe.DollarVolumeUniverse(floor_percentile=90.0,ceiling_percentile=100.0))
    #context.universe = [#sid(698)         #BA
    #    #sid(8554) #SPY
    #    #sid(27098) #ISE

    #    ####################### 9 sector etfs
    #    sid(19662) # XLY Consumer Discrectionary SPDR Fund
    #    ,sid(19656) # XLF Financial SPDR Fund
    #    ,sid(19658) # XLK Technology SPDR Fund
    #    ,sid(19655) # XLE Energy SPDR Fund
    #    ,sid(19661) # XLV Health Care SPRD Fund
    #    ,sid(19657) # XLI Industrial SPDR Fund
    #    ,sid(19659) # XLP Consumer Staples SPDR Fund
    #    ,sid(19654) # XLB Materials SPDR Fund
    #    ,sid(19660) # XLU Utilities SPRD Fund
    #    ]

    #aprox 200 SPY constituents from fetcher
    #fetch_csv(
    #   "https://googledrive.com/host/0BwZ2bMDOKaeDYWYzYzgxNDYtNmQyYi00ZDk5LWE3ZTYtODQ0ZDAzNTBkY2M4/trading/SP500-20131001.csv",
    #    pre_func=preview,
    #    date_column='date',
    #    universe_func=(my_universe))
    #aprox 90 hardcoded SPY constituents
    #my_static_universe(context) 

    ########## COMMISSION
    #use top to decrease uncertainty when testing algorithms
    #set_commission(commission.PerShare(cost=0.0))
    #set_commission(commission.PerShare(cost=0.005, min_trade_cost=1.00)) #IB
    #fixed commission model
    #set_commission(commission.PerShare(cost=0.013, min_trade_cost=1.3)) #more
    #agressive...
    
    ########## SLIPPAGE
    #use top to decrease uncertainty when testing algorithms
    #set_slippage(slippage.FixedSlippage(spread=0.00))
    #set_slippage(slippage.FixedSlippage(spread=0.01))
    #set_slippage(WorstSpreadSlippage())
    #set_slippage(CustomSlippage(1.0,0.0))

    ############# Anony values
    set_commission(commission.PerTrade(cost=1.0))
    set_slippage(TradeAtTheOpenSlippageModel_Simple(0.1))

##############  USERCODE BELOW.  EDIT BELOW THIS LINE
##############  USERCODE BELOW.  EDIT BELOW THIS LINE
##############  USERCODE BELOW.  EDIT BELOW THIS LINE


class BBTechnicalIndicators(FrameHistory):
    '''technical indicators relating to bollinger bands'''
    class State:
        '''State recorded for each frame (minute).  number of frames history we store is determined by framework.maxHistoryFrames'''
        def __init__(this,parent, security, data):
            this.parent = parent
            this.security = security
            this.history = this.parent.state

            bb = this.parent.bbands_data[this.security.sid]
            #will be NaN if not enough period
            this.upperLimit = bb[0]
            this.line = bb[1]
            this.lowerLimit = bb[2]
            #see https://www.tradingview.com/stock-charts-support/index.php/Bollinger_Bands_%25B_(%25B)
            this.percentB = (this.security.standardIndicators.state[0].close_price - this.lowerLimit) / (this.upperLimit - this.lowerLimit)
            #see https://www.tradingview.com/stock-charts-support/index.php/Bollinger_Bands_Width_(BBW)
            this.bbw = (this.upperLimit - this.lowerLimit) / this.line
            #track slope of %B, to determine if rising (positive) or falling (negative)
            if len(this.history) > 0:
                this.percentBSlope = (this.percentB - this.history[0].percentB)
                this.bbwSlope = (this.bbw - this.history[0].bbw)
                this.percentBPercentile = scipy.stats.percentileofscore([state.percentB for state in this.history],this.percentB,"mean") / 100.0
                this.bbwPercentile = scipy.stats.percentileofscore([state.bbw for state in this.history],this.bbw,"mean") / 100.0 
                this.lineSlope = (this.line - this.history[0].line)
            else:
                this.percentBSlope = 0.0
                this.bbwSlope = 0.0
                this.percentBPercentile = 0.5
                this.bbwPercentile = 0.5
                this.lineSlope = 0.0

            #track momentum
            if this.percentB > 0.8:
                if len(this.history) > 0:
                    this.upperMomentumTicks = this.history[0].upperMomentumTicks + 1
                else:
                    this.upperMomentumTicks = 1
            else:
                this.upperMomentumTicks = 0            
            if this.percentB < 0.2:
                if len(this.history) > 0:
                    this.lowerMomentumTicks = this.history[0].lowerMomentumTicks + 1
                else:
                    this.lowerMomentumTicks = 1
            else:
                this.lowerMomentumTicks = 0





            #logger.debug(" bb for {0} is {1}".format(this.security.symbol, bb));
            
            #logger.recordNormalized("upperLimit",this.upperLimit,this.security.security_start_price)
            #logger.recordNormalized("line",this.line,this.security.security_start_price)
            #logger.recordNormalized("lowerLimit",this.lowerLimit,this.security.security_start_price)

            #logger.record("upperBar",1.0)
            #logger.record("lowerBar",0.0)
            #logger.record("upperApproach",0.8)
            #logger.record("lowerApproach",0.2)
            #logger.record("percentB",this.percentB);

        def __repr__(this):
            return "{0} @ {1} BBANDS l={2:.2f} \t upper={3:.2f} lower={4:.2f}".format(this.security.symbol, this.datetime, this.line, this.upperLimit, this.lowerLimit)


    def initialize(this, data):
        this.bbands = ta.BBANDS(timeperiod=20,nbdevup=2, nbdevdn=2,matype=0) #output: Dictionary of sid to tuples, where each tuple is three floats: (upperLimit, line, lowerLimit).
        this.bbands_data = this.bbands(data)
        pass
    
    def constructFrameState(this,data):
        #logger.debug("BBTechnicalIndicators.constructFrameState")
        currentState = BBTechnicalIndicators.State(this, this.parent, data)
        return currentState

class StandardIndicators(FrameHistory):
    '''common technical indicators that we plan to use for any/all strategies
    feel free to extend this, or use as a reference for constructing specialized technical indicators'''
    class State:
        '''State recorded for each frame (minute).  number of frames history we store is determined by framework.maxHistoryFrames'''
        def __init__(this,parent, security, data):
            this.parent = parent
            this.security = security
            this.history = this.parent.state

            #preset for proper intelisence
            this.datetime = datetime.datetime.now()
            this.open_price = 0.0
            this.close_price = 0.0
            this.high = 0.0
            this.low = 0.0
            this.volume = 0

            #this.mavg3 = 0.0
            #this.mavg7 = 0.0
            #this.mavg15 = 0.0
            #this.mavg30 = 0.0
            #this.mavg45 = 0.0
            #this.mavg60 = 0.0

            #this.stddev3 = 0.0
            #this.stddev7 = 0.0
            #this.stddev15 = 0.0
            #this.stddev30 = 0.0
            #this.stddev45 = 0.0
            #this.stddev60 = 0.0

            this.datetime = data[this.security.qsec].datetime
            this.open_price = data[this.security.qsec].open_price
            this.close_price = data[this.security.qsec].close_price
            this.high = data[this.security.qsec].high
            this.low = data[this.security.qsec].low
            this.volume = data[this.security.qsec].volume
                        
            
            #mavg for last x minutes
            #this.mavg3 = numpy.mean([state.close_price for state in
            #this.history[0:3]])
            #this.mavg7 = numpy.mean([state.close_price for state in
            #this.history[0:7]])
            #this.mavg15 = numpy.mean([state.close_price for state in
            #this.history[0:15]])
            #this.mavg30 = numpy.mean([state.close_price for state in
            #this.history[0:30]])
            #this.mavg45 = numpy.mean([state.close_price for state in
            #this.history[0:45]])
            #this.mavg60 = numpy.mean([state.close_price for state in
            #this.history[0:60]])

            #this.stddev3 = numpy.std([state.close_price for state in
            #this.history[0:3]])
            #this.stddev7 = numpy.std([state.close_price for state in
            #this.history[0:7]])
            #this.stddev15 = numpy.std([state.close_price for state in
            #this.history[0:15]])
            #this.stddev30 = numpy.std([state.close_price for state in
            #this.history[0:30]])
            #this.stddev45 = numpy.std([state.close_price for state in
            #this.history[0:45]])
            #this.stddev60 = numpy.std([state.close_price for state in
            #this.history[0:60]])

            if len(this.history) < 1:                
                this.returns = 0.0
                this.returns_median_abs = 0.0
            else:
                #always returns compared to last timestep
                this.returns = (this.close_price - this.history[0].close_price) / this.history[0].close_price
                if len(this.history) == 1:
                    this.returns_median_abs = abs(this.returns)
                else:
                    this.returns_median_abs = numpy.median([abs(state.returns) for state in this.history])

            try:                
                #when in intraday mode, stores cumulative returns through the day
                this.returns_today = data[this.security.qsec].returns()
            except:
                this.framework.logger.error("{0} unable to obtain returns()  setting returns to zero  open={1}.  close = {2}".format(this.parent.qsec, this.open_price, this.close_price))
                this.returns_today = 0.0
            pass

            #daily accumulations
            if this.security.framework.thisFrameDay != this.security.framework.lastFrameDay or len(this.history) < 1:
                this.open_price_today = this.open_price
                #if len(this.history) < 1:
                    
                #    this.open_price_yesterday = this.open_price_today
                #    this.close_price_yesterday = this.close_price
                #    this.returns_yesterday = this.returns_today
                ##new day, so record our start of day values
                #else:
                #    this.open_price_yesterday =
                #    this.history[0].open_price_today
                #    this.close_price_yesterday = this.history[0].close_price
                #    this.returns_yesterday = this.history[0].returns_today
            else:
                this.open_price_today = this.history[0].open_price_today
                #this.open_price_yesterday =
                #this.history[0].open_price_yesterday
                #this.close_price_yesterday =
                #this.history[0].close_price_yesterday
                #this.returns_yesterday = this.history[0].returns_yesterday

        def __repr__(this):
            return "{0} @ {1} c={0}".format(this.security.symbol, this.datetime, this.close_price)

    def initialize(this, data):
        pass
    
    def constructFrameState(this,data):
        #logger.debug("StandardTechnicalIndicators.constructFrameState")
        currentState = StandardIndicators.State(this, this.parent, data)
        return currentState


class DailyTechnicalIndicators(FrameHistory):
    '''standard technical indicators for the entire day
    for daily history.   the .state[] history does not include the current day, only previous days'''
    class State:
        '''State recorded for each previous day.  number of frames history we store is determined by framework.maxHistoryFrames'''
        def __init__(this,parent, security, data):
            this.parent = parent
            this.security = security
            this.history = this.parent.state



            #preset for proper intelisence
            this.datetime = datetime.datetime.now()


            #setting these to default to yesterday's value so that for the
            #first day of our simulation we get reasonable values
            this.open_price = data[this.security.qsec].mavg(1)
            this.close_price = this.open_price
            #this.high = 0.0
            #this.low = 0.0
            #this.volume = 0

            #this.mavg3 = this.open_price
            #this.mavg7 = this.open_price
            #this.mavg15 = this.open_price
            #this.mavg30 = this.open_price
            #this.mavg45 = this.open_price
            #this.mavg60 = this.open_price

            #this.stddev3 = this.open_price
            #this.stddev7 = this.open_price
            #this.stddev15 = this.open_price
            #this.stddev30 = this.open_price
            #this.stddev45 = this.open_price
            #this.stddev60 = this.open_price

            
            if this.security.simFrame != 0:
                #assert(this.security.standardIndicators.state[1].simFrame+1 ==
                #this.security.simFrame,"expect to be previous day")
            
                this.datetime = this.security.standardIndicators.state[1].datetime
                this.open_price = this.security.standardIndicators.state[1].open_price_today
                this.close_price = this.security.standardIndicators.state[1].close_price
                this.returns = this.security.standardIndicators.state[1].returns_today

            
            #mavg for last x days
            #this.mavg3 = data[this.security.qsec].mavg(3)
            #this.mavg7 = data[this.security.qsec].mavg(7)
            #this.mavg15 = data[this.security.qsec].mavg(15)
            #this.mavg30 = data[this.security.qsec].mavg(30)
            #this.mavg45 = data[this.security.qsec].mavg(45)
            #this.mavg60 = data[this.security.qsec].mavg(60)

            #this.stddev3 = data[this.security.qsec].stddev(3)
            #this.stddev7 = data[this.security.qsec].stddev(7)
            #this.stddev15 = data[this.security.qsec].stddev(15)
            #this.stddev30 = data[this.security.qsec].stddev(30)
            #this.stddev45 = data[this.security.qsec].stddev(45)
            #this.stddev60 = data[this.security.qsec].stddev(60)

        def __repr__(this):
            return "c={0} mavg7={1} mavg30={2}".format(this.close_price,this.mavg7,this.mavg30)

    def initialize(this, data):
        pass
    
    def constructFrameState(this,data):
        #logger.debug("StandardTechnicalIndicators.constructFrameState")

        if this.framework.thisFrameDay == this.framework.lastFrameDay:
            #keep previous
            currentState = None
        else:
            currentState = DailyTechnicalIndicators.State(this, this.parent, data)

        return currentState
    pass



class VolatilityBiasIndicators(FrameHistory):
    ''' custom indicators used by the volatility bias strategy '''
    def initialize(this, data):
        
        pass
    
    def setWindow(this, trendPeriods, weightPeriods, triggerPeriods):
        '''set the size of the window our volatilityBias cares about
        trendPeriods #state.trend = percent the range is up, exponential weighted by timestep
        weightPeriods #state.weight = percent the range is up, linear weighted by timestep
        triggerPeriods #state.trigger = percent the range is up, linear weighted by timestep
        '''

        #internal variables
        this.trendPeriods = trendPeriods #the max history we will care about, used for determining the value of the state.trend variable
        this.weightPeriods = weightPeriods
        this.triggerPeriods = triggerPeriods
        
        this.framework.ensureMinHistory(this.trendPeriods)
        this.framework.ensureMinHistory(this.weightPeriods)
        this.framework.ensureMinHistory(this.triggerPeriods)

    '''technical indicators relating to bollinger bands'''
    class State:
        '''State recorded for each frame (minute).  number of frames history we store is determined by framework.maxHistoryFrames'''
        def __init__(this,parent, security, data):
            this.parent = parent
            this.security = security
            this.history = this.parent.state

            

            this.setWeight()

        def setWeight(this):
            '''computes weight by taking the price range (high-low) for each timestep, and summing them based on linear weight (most recient = more weight)'''
            #pretty confident in this port being accurate
            security = this.security
            stdState = security.standardIndicators.state
            stdStateLen = len(stdState)

            #set default values
            if len(this.history)== 0:
                this.weight = 0.0
                this.trend = 0.0
                this.trigger = 0.0
                return
            else:
                #set initial value equal to previous values
                this.weight = this.history[0].weight
                this.trend = this.history[0].trend
                this.trigger = this.history[0].trigger

            #SET state.trend
            #trading range linear weighted by timestep
            upPortion = 0.0
            downPortion = 0.0
            span = this.parent.trendPeriods if stdStateLen > this.parent.trendPeriods else stdStateLen
            for i in range(0,span):
                if stdState[i].close_price > stdState[i].open_price:
                    upPortion += ((span-i) * (stdState[i].high - stdState[i].low));  
                else:
                    downPortion +=((span-i) * (stdState[i].high - stdState[i].low));  
            if (upPortion + downPortion > 0.0):
                factor = upPortion / (upPortion + downPortion)
                #trend = percent the range is up, exponential weighted by timestep
                this.trend = (this.history[0].trend + factor) / 2.0
            #logger.info("sec={0} \t span={1} upP={2} dwnP={3} fac={4} trend={5}".format(this.security.symbol,span,upPortion,downPortion, factor, this.trend))
            #SET state.weight
            if stdStateLen > this.parent.weightPeriods:                
                upPortion = 0.0
                downPortion = 0.0
                span = this.parent.weightPeriods
                for i in range(0,span):
                    if stdState[i].close_price > stdState[i].open_price:
                        upPortion += ((span-i) * (stdState[i].high - stdState[i].low));  
                    else:
                        downPortion +=((span-i) * (stdState[i].high - stdState[i].low));  
                if (upPortion + downPortion > 0.0):
                    factor = upPortion / (upPortion + downPortion)
                    #weight = percent the range is up, linear weighted by timestep
                    this.weight = factor

            #SET state.trigger
            if stdStateLen > this.parent.triggerPeriods:                
                upPortion = 0.0
                downPortion = 0.0
                span = this.parent.triggerPeriods
                for i in range(0,span):
                    if stdState[i].close_price > stdState[i].open_price:
                        upPortion += ((span-i) * (stdState[i].high - stdState[i].low));  
                    else:
                        downPortion +=((span-i) * (stdState[i].high - stdState[i].low));  
                if (upPortion + downPortion > 0.0):
                    factor = upPortion / (upPortion + downPortion)
                    #trigger = percent the range is up, linear weighted by timestep
                    this.trigger = factor

            return this.weight

        def __repr__(this):
            return "{0} @ {1} VOLBIAS weight={2:.2f} \t trend={3:.2f} trigger={4:.2f}".format(this.security.symbol, this.datetime, this.weight, this.trend, this.trigger)
            


    
    def constructFrameState(this,data):
        #logger.debug("VolatilityBiasIndicators.constructFrameState")
        currentState = VolatilityBiasIndicators.State(this, this.parent, data)
        return currentState    

class VolatilityBiasStrategy():
    def __init__(this, framework, data):
        this.framework = framework


        pass

    def initialize(this,data):
        
        this.trendPeriods = 53
        this.weightPeriods = 33
        this.triggerPeriods = 4

        #this.universe = this.framework._getOrCreateSecurities([
        #    sid(12915) # MDY SPDR S&P MIDCAP 400 ETF TRUST
        #    ,sid(19654) # XLB Materials Select Sector SPDR 
        #    ,sid(19655) # XLE Energy Select Sector SPDR
        #    ,sid(19656) # XLF Financial Select Sector SPDR 
        #    ,sid(19657)# XLI Industrial Select Sector SPDR
        #    ,sid(19658)#XLK  Industrial Select Sector SPDR
        #    ,sid(19659) # XLP  Consumer Staples Select Sector SPDR
        #    ,sid(19660)# XLU Utilities Select Sector SPDR
        #    ,sid(19661)# XLV Utilities Select Sector SPDR
        #    ,sid(19662) # XLY Consumer Discretionary Select Sector SPDR
        #    ,sid(25485) # AGG ISHARES CORE U.S. AGGREGATE BONDS
        #    ],data)

        this.universe = this.framework._getOrCreateSecurities([
            sid(19920) # QQQ
            , sid(2174) # DIA
            , sid(24705) # ISHARES MSCI EMERGING MARKETS "EEM"
            , sid(22972) # ISHARES MSCI EAFE ETF "EFA"
            , sid(24744) # GUGGENHEIM S&P 500 EQUAL WEIGH "RSP",
            , sid(19654) # Materials Select Sector SPDR              "XLB"
            , sid(19655) # Energy Select Sector SPDR                 "XLE"
            , sid(19656) # Financial Select Sector SPDR              "XLF"
            , sid(19657) # Industrial Select Sector SPDR             "XLI"
            , sid(19658) # Technology Select Sector SPDR            "XLK"
            , sid(19659) # Consumer Staples Select Sector SPDR        "XLP"
            , sid(19660) # Utilities Select Sector SPDR              "XLU"
            , sid(19661) # Healthcare Select Sector SPDR            "XLV"
            , sid(19662) # Consumer Discretionary Select Sector SPDR "XLY"
            , sid(22739) # VANGUARD TOTAL STOCK MARKET ETF "VTI"
            , sid(25901) # VANGUARD SMALL-CAP VALUE ETF "VBR"
            , sid(25485) # ISHARES CORE U.S. AGGREGATE BONDS "AGG"
     
            ,  sid(2)     #   Alcoa "AA"
            , sid(679)   #   Amex "AXP"
            ,  sid(698)   #   BOEING CO   "BA"
            , sid(700)   #   BANK OF AMERICA CORP   "BAC"
            , sid(734)   #   BAXTER INTERNATIONAL INC   "BAX"
            , sid(1267)  #   CATERPILLAR INC   "CAT"
            ,sid(1900)  #   CISCO SYSTEMS INC   "CSCO"
            , sid(23112) #   CHEVRON CORPORATION   "CVX"
            ,  sid(2119)  #   DU PONT DE NEMOURS E I &CO   "DD"
            , sid(2190)  #   WALT DISNEY CO-DISNEY COMMON   "DIS"
            , sid(8347)  #   EXXON MOBIL CORPORATION          "XOM"
            ,  sid(3149)  #   GENERAL ELECTRIC CO     "GE"
            ,  sid(3496)  #   HOME DEPOT INC  "HD"
            , sid(3735)  #   HEWLETT-PACKARD CO   "HPQ"
            , sid(3766)  #   INTL BUSINESS MACHINES CORP   "IBM"
            ,sid(3951)  #   INTEL CORP   "INTC"
            , sid(4151)  #   JOHNSON AND JOHNSON   "JNJ"
            , sid(25006) #   JPMORGAN CHASE & CO COM STK   "JPM"
            ,  sid(4283)  #   COCA-COLA CO   "KO"
            , sid(4707)  #   MCDONALDS CORP   "MCD"
            , sid(4922)  #   3M COMPANY   "MMM"
            , sid(5029)  #   MERCK & CO IN C  "MRK"
            ,sid(5061)  #   MICROSOFT CORP   "MSFT"
            , sid(5923)  #   PFIZER INC   "PFE"
            ,  sid(5938)  #   PROCTER & GAMBLE CO   "PG"
            ,   sid(6653)  #   AT&T INC.COM   "T"
            , sid(24845) #   Travelers "TRV"
            , sid(7792)  #   UNITEDHEALTH GROUP INC  "UNH"
            , sid(7883)  #   UNITED TECHNOLOGIES CORP   "UTX"
            ,  sid(21839) #   VERIZON COMMUNICATIONS   "VZ"
            , sid(8229)  #   WAL-MART STORES INC  "WMT"
    ],data)

    def update(this, data):
        
        if this.framework.simFrame < (this.weightPeriods -1):
            #ensure we have our history populated
            return

        totalWeight = 0
        entries = [] #securities we will open positions with
        exits = [] #open positions we will close

        securitiesToEnumerate = this.framework.activeSecurities.items()

        for sid,security in securitiesToEnumerate:
            enter = False
            exit = False
            if security.isActive==False:
                continue

            volBiasState = security.volBiasIndicators.state[0]
            
            if volBiasState.weight - volBiasState.trigger >= 0.40 and volBiasState.trend > 0.50:
                enter = True
            elif security.volatilityBiasStrategyPosition._currentCapitalSharePercent > 0.0:
                if volBiasState.trigger > 0.50 and volBiasState.trigger < 0.80:
                    enter = True
                else: 
                    exit = True
            else:
                exit = True

            if enter:                
                totalWeight += volBiasState.weight
                entries.append(security)
            if exit:
                exits.append(security)
                pass
            pass
        enterCount = len(entries)
        if enterCount > 0:
            for security in entries:
                #rebalance based on weights
                security.volBiasIndicators.state[0].weight /= totalWeight
                security.volatilityBiasStrategyPosition.targetCapitalSharePercent = security.volBiasIndicators.state[0].weight
        for security in exits:
            security.volatilityBiasStrategyPosition.targetCapitalSharePercent = 0.0
            pass

        for sid,security in securitiesToEnumerate:
            #execute trades for this timestep
            security.volatilityBiasStrategyPosition.processOrder(data)
            
        logger.record("Weight",this.universe[0].volBiasIndicators.state[0].weight)
        logger.record("Trigger",this.universe[0].volBiasIndicators.state[0].trigger)
        logger.record("Trend",this.universe[0].volBiasIndicators.state[0].trend)
            
       



    
    
class ExampleFramework(FrameworkBase):
    def initialize(this, data):
        
        this.volatilityBiasStrategy = VolatilityBiasStrategy(this,data)
        this.volatilityBiasStrategy.initialize(data)
        
        #this.spy = this._getOrCreateSecurity(sid(8554), data) #SPY
        

        pass

    def initializeFirstUpdate(this, data):
        #this.ensureMinHistory(360)
        pass

    def initializeSecurity(this,security, data):
        security.standardIndicators = StandardIndicators(security,this, data)
        #security.dailyIndicators = DailyTechnicalIndicators(security,this)
        security.volBiasIndicators = VolatilityBiasIndicators(security,this, data)
        #set our securities to use the same window sizes based on a global config
        security.volBiasIndicators.setWindow(this.volatilityBiasStrategy.trendPeriods, this.volatilityBiasStrategy.weightPeriods, this.volatilityBiasStrategy.triggerPeriods)
        security.volatilityBiasStrategyPosition = StrategyPosition(security,"volatilityBiasStrategyPosition")
        
        
        pass

    def update(this, data):
        #update all security indicators
        for sid,security in this.activeSecurities.items():
            security.standardIndicators._update(data)
            #security.dailyIndicators._update(data)
            security.volBiasIndicators._update(data)
            pass

        this.volatilityBiasStrategy.update(data)

        #logger.record("tradesD100",this._totalTrades / 100.0)

    pass





##############  CONFIGURATION BELOW
def constructFramework(context,data):
    '''factory method to return your custom framework/trading algo'''
    return ExampleFramework(context,data)

There was a runtime error.

Here's a variant, run on minute bars. A couple notes:

--No commissions (set_commission(commission.PerShare(cost=0.0)))
--As I understand, Quantopian still cancels orders at the day's end, so it won't work as written in live trading

Hopefully, the code is readable. Questions/comments/improvements welcome.

Grant

Clone Algorithm
25
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
# https://www.quantopian.com/posts/volatility-bias-up-range-slash-total-range-strategy

import numpy as np
from pytz import timezone
import pandas as pd
from scipy import stats

trading_freq = 1 # trading frequency, days

def initialize(context):
    context.stocks = [ sid(19654),  # Materials Select Sector SPDR             
                       sid(19655),  # Energy Select Sector SPDR                
                       sid(19656),  # Financial Select Sector SPDR             
                       sid(19657),  # Industrial Select Sector SPDR            
                       sid(19658),  # Technology Select Sector SPDR            
                       sid(19659),  # Consumer Staples Select Sector SPDR      
                       sid(19660),  # Utilities Select Sector SPDR             
                       sid(19661),  # Healthcare Select Sector SPDR            
                       sid(19662),  # Consumer Discretionary Select Sector SPDR
                       sid(8554) ]  # SPY
    
    context.day_count = -1
    
    context.allocation = -1.0*np.ones_like(context.stocks)
    
    set_commission(commission.PerShare(cost=0.0))

def handle_data(context, data):
    
    # Trade only once per day
    loc_dt = get_datetime().astimezone(timezone('US/Eastern'))
    if loc_dt.hour == 16 and loc_dt.minute == 0:
        context.day_count += 1
        pass
    else:
        return
    
    # Limit trading frequency
    if context.day_count % trading_freq != 0.0:
        return
    
    # Get indicators
    trend = VolBias(context,50)
    weight = VolBias(context,30)
    trigger = VolBias(context,5)
    
    if trend == None or weight == None or trigger == None:
        return
    
    delta = weight - trigger
    
    weight = 1.0 - weight
    
    # Normalize w/ z-score
    trend = stats.zscore(trend, axis=0, ddof=1)
    trigger = stats.zscore(trigger, axis=0, ddof=1)
    delta = stats.zscore(delta, axis=0, ddof=1)    
    
    record(trend = trend[0], trigger = trigger[0], delta = delta[0])
    
    allocation = 0.0*np.zeros_like(weight)
    for i,stock in enumerate(context.stocks[0:-1]):
        allocation[i] = context.portfolio.positions[stock].amount
        
    for i in range(len(context.stocks)-1):
        if allocation[i] > 0.0:
            if abs(trigger[i]) < 1.5:
                allocation[i] = weight[i]
            else:
                allocation[i] = 0.0
        elif delta[i] > 1 and trend[i] > 1.5:
            allocation[i] = weight[i]
        else:
            allocation[i] = 0.0
    
    denom = np.sum(allocation)
    if denom != 0.0:
        allocation = allocation/np.sum(allocation)
        
    # return if allocation unchanged
    if np.array_equal(context.allocation,allocation):
        return
    
    context.allocation = allocation
    
    for stock,percent in zip(context.stocks[0:-1],allocation):
        order_target_percent(stock,percent)
        
def VolBias(context,n):
    
    # Get daily bar data and intraday values per Quantopian help history specs
    opn = history(90,'1d','open_price').fillna(method='ffill').as_matrix(context.stocks)
    close = history(90,'1d','close_price').fillna(method='ffill').as_matrix(context.stocks)
    low = history(90,'1d','low').fillna(method='ffill').as_matrix(context.stocks)
    high = history(90,'1d','high').fillna(method='ffill').as_matrix(context.stocks)
    
    # Check for nans
    if np.isnan(np.sum(opn)):
        return None
    if np.isnan(np.sum(close)):
        return None
    if np.isnan(np.sum(low)):
        return None
    if np.isnan(np.sum(high)):
        return None
    
    # Daily peak-to-peak range and close relative to open
    rng = high - low 
    cls_opn = close - opn
    
    # Matrix of sign of cls_opn
    up_down = np.sign(cls_opn)
    
    # Create up mask
    up = np.copy(up_down)
    up[up < 0] = 0
    
    # Create down mask
    down = np.copy(up_down)
    down[down > 0] = 0
    
    # Apply masks to peak-to-peak range
    rng_up = np.multiply(rng,up)
    rng_down = np.multiply(rng,-down)
    
    # Compute volatility bias indicator
    denom = pd.ewma(rng_up,span=n) + pd.ewma(rng_down,span=n)  
    vb = (pd.ewma(rng_up,span=n)/denom)[-1,:]
    
    # Return indicator relative to benchmark
    return vb[0:-1]-float(vb[-1])
There was a runtime error.