Back to Community
Another way to rebalance - simple price and volume return
Clone Algorithm
24
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
import collections

def initialize(context):
    context.Stocks = SecurityManager()
    context.Stocks.Add("EWA", sid(14516))
    context.Stocks.Add("EWC", sid(14517))
    context.Stocks.Add("EWD", sid(12430))
    context.Stocks.Add("EWG", sid(14518))
    context.Stocks.Add("EWH", sid(14519))
    context.Stocks.Add("EWI", sid(25098))
    context.Stocks.Add("EWJ", sid(14520))
    context.Stocks.Add("EWK", sid(14521))
    context.Stocks.Add("EWL", sid(14522))
    context.Stocks.Add("EWM", sid(14523))
    context.Stocks.Add("EWN", sid(14524))
    context.Stocks.Add("EWO", sid(14525))
    context.Stocks.Add("EWP", sid(14526))
    context.Stocks.Add("EWQ", sid(14527))
    context.Stocks.Add("EWS", sid(14528))
    context.Stocks.Add("EWT", sid(21619))
    context.Stocks.Add("EWU", sid(14529))
    context.Stocks.Add("EWW", sid(14530))
    context.Stocks.Add("EWY", sid(21491))
    context.Stocks.Add("EWZ", sid(21757))
    context.Stocks.Add("EZA", sid(24611))
    context.Stocks.Add("FXI", sid(26703))
    context.Stocks.Add("IWD", sid(21517))
    context.Stocks.Add("IWN", sid(21785))
    context.Stocks.Add("AGG", sid(25485))
    context.Stocks.Add("BND", sid(18387))
    context.Stocks.Add("SHY", sid(23911))

    context.dayCount = 0
    
    set_commission(commission.PerTrade(cost=1.0))
    set_slippage(TradeAtTheOpenSlippageModel(.1))

def handle_data(context, data):
    context.Stocks.Update(data)
    context.dayCount += 1
    if (context.dayCount < 2):
        return
    for security in context.Stocks.GetSecurities():
        if (security.Enabled):
            order_target_percent(security.Sid, security.Weight)
            

################################################################                
class SecurityManager(object):
    '''Class to wrap securities'''

    def __init__(self):
        try:
            self.stockList = {}
            
        except Exception, err:
            print "Exception creating securities:\n\t{0}".format(err)

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

    def Update(self, data):
        totalWeight = 0
        for sec in self.stockList.values():
            if sec.Sid not in data:
                sec.Enabled = False
                continue
            sec.PriorPrice = sec.CurrentPrice
            sec.PriorVolume = sec.CurrentVolume
            sec.CurrentPrice = data[sec.Sid].close_price
            sec.CurrentVolume = data[sec.Sid].volume
            sec.Enabled = True            
            totalWeight += sec.SetWeight()
        
        i = float(1.0)
        count = float(self.Count())
        fraction = i / count
        weightFraction = totalWeight / count
        self.stockList = collections.OrderedDict(sorted(self.stockList.items(), key=lambda sec: sec[1].Weight))
        
        for sec in self.stockList.values():
            if (sec.Weight > 0):
                sec.Weight = (count - i) / count * fraction
                i += 1.0 - weightFraction
            else:
                sec.Weight = -(count - i) / count * fraction
                i -= 1.0 + weightFraction
        
    def GetSecurities(self):
        return self.stockList.values()
    
#################################################################
class Security(object):
    '''Class to wrap security'''

    def __init__(self, symbol, sid):
        try:
            self.Symbol = symbol
            self.Sid = sid
            self.CurrentPrice = 1
            self.PriorPrice = 1
            self.CurrentVolume = 1
            self.PriorVolume = 1
            self.Weight = 0
            self.Enabled = True
            
        except Exception, err:
            print "Exception creating security:\n\t{0}".format(err)

    def __str__(self):
        toString = "\tSymbol:{0}\n".format(self.symbol)
        return toString 

    def SetWeight(self):
        priceWeight = (self.CurrentPrice - self.PriorPrice) / self.PriorPrice
        volumeWeight = (float(self.CurrentVolume) - float(self.PriorVolume)) / float(self.PriorVolume)
        if (priceWeight > 0):
            if (volumeWeight > 0):
                self.Weight = priceWeight + volumeWeight;
            else:
                self.Weight = priceWeight + volumeWeight / 2;
        else:
            if (volumeWeight < 0):
                self.Weight = priceWeight + volumeWeight;
            else:
                self.Weight = priceWeight + volumeWeight / 2;
        return self.Weight
        
########################################################    
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
        if (ocRange != 0.0):
            targetExecutionPrice = openPrice + ocRange
        else:
            targetExecutionPrice = openPrice
            
        # Create the transaction using the new price we've calculated.
        return slippage.create_transaction(
            trade_bar,
            order,
            targetExecutionPrice,
            order.amount
        )

        
        
        
        
        
        
        
        
        
        
        
        
        
        
This backtest was created using an older version of the backtester. Please re-run this backtest to see results using the latest backtester. Learn more about the recent changes.
There was a runtime error.
1 response

Thanks Anony,

Your TradeAtTheOpenSlippageModel thingy is slick. I gather that is allows one to basically set the fill price arbitrarily when backtesting (if only one could get it to work under live trading). I'm wondering if it would work to fix the problem of how the backtester fills limit/stop orders. Under live trading, the trigger will be evaluated effectively immediately after the order is encountered in the algorithm code, whereas in backtesting (if it works how I think), the trigger is not evaluated until the next bar and if triggered, the order is submitted (and subsequently filled upon the next next bar). So, if I'm reading things correctly, when backtesting, there is way too much latency in filling compared to live trading.

On a separate note, you might be interested in https://www.quantopian.com/posts/finite-state-machine-in-python (Ed Bartosh provides a nice example).

Grant