Back to Community
More messin' with Volatility bias, long and short now.
Clone Algorithm
173
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
import collections

trendPeriods = 50
triggerPeriods = 5
weightsPctChangeThreshold = 5.0

def initialize(context):
    secMgr = SecurityManager()
    secMgr.Add("XLE", sid(19655), 0) # Energy Select Sector SPDR
    secMgr.Add("XLF", sid(19656), 0) # Financial Select Sector SPDR
    secMgr.Add("XLI", sid(19657), 0) # Industrial Select Sector SPDR
    secMgr.Add("XLK", sid(19658), 0) # Technology Select Sector SPDR
    secMgr.Add("XLP", sid(19659), 0) # Consumer Staples Select Sector SPDR
    secMgr.Add("XLU", sid(19660), 0) # Utilities Select Sector SPDR
    secMgr.Add("XLV", sid(19661), 0) # Healthcare Select Sector SPDR
    secMgr.Add("XLY", sid(19662), 0) # Consumer Discretionary Select Sector SPDR
    
    context.SecMgr = secMgr
    context.period = 0
    context.runningPnL = 0.0
    context.priorWeightMean = 0.0
    set_commission(commission.PerTrade(cost=1.0))
    set_slippage(TradeAtTheOpenSlippageModel(0.1))
    
def handle_data(context, data):
    context.period += 1
    totalWeight = context.SecMgr.Update(data)    
    record(PnL=context.portfolio.pnl, RPnl=context.runningPnL, Outlay=context.portfolio.positions_value, Weight=totalWeight)

    if (context.period < trendPeriods):
        return

    securityList = context.SecMgr.GetRankedEnabledSecurities()
    weightMean = totalWeight / float(len(securityList))
    if (weightMean <= 0.0 or context.priorWeightMean == 0.0):
        context.priorWeightMean = weightMean
        return
    if ((abs(weightMean - context.priorWeightMean) / weightMean) * 100.0 < weightsPctChangeThreshold):
        return

    context.priorWeightMean = weightMean
    context.runningPnL = context.portfolio.pnl
    
    securityCount = float(len(securityList))
    entryFraction = 1.0 / securityCount
    for security in securityList:
        if (weightMean > .45):
            if (security.Weight - security.Trigger >= .20):
                order_target_percent(security.Sid, entryFraction)
            else:
                if (security.Weight > .55):
                    order_target_percent(security.Sid, entryFraction)
                else:
                    order_target_percent(security.Sid, -entryFraction / 2.0)
        else:
            if (security.Trigger - security.Weight >= .15):
                order_target_percent(security.Sid, -entryFraction / 2.0)
            else:
                if (security.Weight > .40):
                    order_target_percent(security.Sid, entryFraction)
                else:
                    order_target_percent(security.Sid, entryFraction / 2.0)

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

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

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

    def Update(this, data):
        totalWeight = 0.0
        for sec in this.stockList.values():
            if sec.Sid not in data:
                sec.Weight = 0.0
                sec.Enabled = False
                continue
            sec.UpdatePrices(data)
            sec.SetWeight()
            totalWeight += sec.Weight
        return totalWeight
    
    def GetRankedEnabledSecurities(this):
        returnList = {}
        for sec in this.stockList.values():
            if (sec.Enabled):
                returnList[sec] = sec.Weight
        # dictionary sorted by value
        ranked = collections.OrderedDict(sorted(returnList.items(), key=lambda t: t[1]))
        items = ranked.items()
        items.reverse()
        ranked = collections.OrderedDict(items)        
        return ranked
       
#################################################################
class Security(object):
    '''Class to wrap security'''

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

    def process_order(this, trade_bar, order):
        firstPrice = trade_bar.open_price
        lastPrice = trade_bar.close_price
        hlRange = lastPrice - firstPrice
        hlRange = hlRange * this.fractionOfOpenCloseRange
        targetExecutionPrice = firstPrice + hlRange
            
        # Create the transaction using the new price we've calculated.
        return slippage.create_transaction(
            trade_bar,
            order,
            targetExecutionPrice,
            order.amount
        )    
There was a runtime error.
3 responses

It looks good! Thanks

  • And the returns are much beter than "Rebalance Algo: 9 Sector ETFs" hehehe

Hi Anony. Beware of including 2002/3 and 2009 in back tests. Likewise time frames. Will your algo. still be running in 10 or even 5 years? Best, Tom

Clone Algorithm
1
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
import math
import numpy as np
import collections

trendPeriods = 50
triggerPeriods = 5
weightsPctChangeThreshold = 5.0

def initialize(context):
    secMgr = SecurityManager()
    secMgr.Add("XLE", sid(19655), 0) # Energy Select Sector SPDR
    secMgr.Add("XLF", sid(19656), 0) # Financial Select Sector SPDR
    secMgr.Add("XLI", sid(19657), 0) # Industrial Select Sector SPDR
    secMgr.Add("XLK", sid(19658), 0) # Technology Select Sector SPDR
    secMgr.Add("XLP", sid(19659), 0) # Consumer Staples Select Sector SPDR
    secMgr.Add("XLU", sid(19660), 0) # Utilities Select Sector SPDR
    secMgr.Add("XLV", sid(19661), 0) # Healthcare Select Sector SPDR
    secMgr.Add("XLY", sid(19662), 0) # Consumer Discretionary Select Sector SPDR
    
    context.SecMgr = secMgr
    context.period = 0
    context.runningPnL = 0.0
    context.priorWeightMean = 0.0
    set_commission(commission.PerTrade(cost=1.0))
    set_slippage(TradeAtTheOpenSlippageModel(0.1))
    
def handle_data(context, data):
    context.period += 1
    totalWeight = context.SecMgr.Update(data)    
    record(PnL=context.portfolio.pnl, RPnl=context.runningPnL, Outlay=context.portfolio.positions_value, Weight=totalWeight)

    if (context.period < trendPeriods):
        return

    securityList = context.SecMgr.GetRankedEnabledSecurities()
    weightMean = totalWeight / float(len(securityList))
    if (weightMean <= 0.0 or context.priorWeightMean == 0.0):
        context.priorWeightMean = weightMean
        return
    if ((abs(weightMean - context.priorWeightMean) / weightMean) * 100.0 < weightsPctChangeThreshold):
        return

    context.priorWeightMean = weightMean
    context.runningPnL = context.portfolio.pnl
    
    securityCount = float(len(securityList))
    entryFraction = 1.0 / securityCount
    for security in securityList:
        if (weightMean > .45):
            if (security.Weight - security.Trigger >= .20):
                order_target_percent(security.Sid, entryFraction)
            else:
                if (security.Weight > .55):
                    order_target_percent(security.Sid, entryFraction)
                else:
                    order_target_percent(security.Sid, -entryFraction / 2.0)
        else:
            if (security.Trigger - security.Weight >= .15):
                order_target_percent(security.Sid, -entryFraction / 2.0)
            else:
                if (security.Weight > .40):
                    order_target_percent(security.Sid, entryFraction)
                else:
                    order_target_percent(security.Sid, entryFraction / 2.0)

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

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

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

    def Update(this, data):
        totalWeight = 0.0
        for sec in this.stockList.values():
            if sec.Sid not in data:
                sec.Weight = 0.0
                sec.Enabled = False
                continue
            sec.UpdatePrices(data)
            sec.SetWeight()
            totalWeight += sec.Weight
        return totalWeight
    
    def GetRankedEnabledSecurities(this):
        returnList = {}
        for sec in this.stockList.values():
            if (sec.Enabled):
                returnList[sec] = sec.Weight
        # dictionary sorted by value
        ranked = collections.OrderedDict(sorted(returnList.items(), key=lambda t: t[1]))
        items = ranked.items()
        items.reverse()
        ranked = collections.OrderedDict(items)        
        return ranked
       
#################################################################
class Security(object):
    '''Class to wrap security'''

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

    def process_order(this, trade_bar, order):
        firstPrice = trade_bar.open_price
        lastPrice = trade_bar.close_price
        hlRange = lastPrice - firstPrice
        hlRange = hlRange * this.fractionOfOpenCloseRange
        targetExecutionPrice = firstPrice + hlRange
            
        # Create the transaction using the new price we've calculated.
        return slippage.create_transaction(
            trade_bar,
            order,
            targetExecutionPrice,
            order.amount
        )    
There was a runtime error.

yea, we're not talking george soros type returns here