Overall Statistics
Total Trades
2495
Average Win
0.33%
Average Loss
-0.16%
Compounding Annual Return
14.670%
Drawdown
18.000%
Expectancy
0.722
Net Profit
330.540%
Sharpe Ratio
1.079
Loss Rate
43%
Win Rate
57%
Profit-Loss Ratio
2.05
Alpha
0.16
Beta
-0.705
Annual Standard Deviation
0.135
Annual Variance
0.018
Information Ratio
0.932
Tracking Error
0.135
Treynor Ratio
-0.207
Total Fees
$3926.54
from clr import AddReference
AddReference("System")
AddReference("QuantConnect.Common")
AddReference("QuantConnect.Algorithm.Framework")

from System import *
from QuantConnect import *
from QuantConnect.Orders import *
from QuantConnect.Algorithm.Framework.Execution import ExecutionModel
from QuantConnect.Algorithm.Framework.Portfolio import PortfolioTargetCollection
from datetime import datetime, timedelta
from pytz import utc
UTCMIN = datetime.min.replace(tzinfo=utc)

class Zero_Leverage_ExecutionModel(ExecutionModel):

    def __init__(self, resolution = Resolution.Daily, min_order = 0):
        
        self.targetsCollection = PortfolioTargetCollection()
        self.finished = False
        self.rebalancingTime = UTCMIN
        self.rebalancingPeriod = Extensions.ToTimeSpan(resolution)
        self.min_order_value = min_order

    def Execute(self, algorithm, targets):
        
        #Run until all orders are completed once per day
        if self.finished and algorithm.UtcTime <= self.rebalancingTime:
            return
        elif algorithm.UtcTime > self.rebalancingTime:
            self.finished = False
            self.rebalancingTime = algorithm.UtcTime + self.rebalancingPeriod
            
        self.targetsCollection.AddRange(targets)
        
        sold = False
        bought = False
        
        for target in self.targetsCollection.OrderByMarginImpact(algorithm):
            
            open_quantity = sum([x.Quantity for x in algorithm.Transactions.GetOpenOrders(target.Symbol)])
            existing = algorithm.Securities[target.Symbol].Holdings.Quantity + open_quantity
            qty_to_order = target.Quantity - existing
            value = abs(qty_to_order) * algorithm.Securities[target.Symbol].Price
            
            #Only sell if it exeeds min order value or if selling everything, to prevent being left with a tiny amount of stock unable to sell
            if qty_to_order <= -1.0 and (value >= self.min_order_value or target.Quantity == 0):
                
                algorithm.MarketOrder(target.Symbol, qty_to_order)
                #algorithm.Debug("Sell = " + str(target.Symbol) + " > " + str(quantity))
                sold = True
            
            #Only buy if it exeeds min order value and no sells have also processed in this same instant to avoid leverage    
            elif qty_to_order >= 1.0 and value >= self.min_order_value and sold == False:
                
                #Don't buy stocks if there are still open sell orders to prevent leverage
                all_open_sells_value = 0
                for order in algorithm.Transactions.GetOpenOrders():
                    
                    if order.Quantity < 0:
                        all_open_sells_value += abs(order.Quantity) * algorithm.Securities[order.Symbol].Price
                        
                if all_open_sells_value == 0:
                    algorithm.MarketOrder(target.Symbol, qty_to_order)
                    #algorithm.Debug("Buy = " + str(target.Symbol) + " > " + str(quantity))
                    bought = True
                else:
                    bought = True
                    
        if bought == False and sold == False:
            self.finished = True
            
        
        
        self.targetsCollection.ClearFulfilled(algorithm)
from clr import AddReference
AddReference("QuantConnect.Algorithm.Framework")
AddReference("QuantConnect.Indicators")
AddReference("QuantConnect.Common")

from QuantConnect import *
from QuantConnect.Indicators import *
from QuantConnect.Algorithm.Framework.Alphas import *

from Utility_Functions import *
from datetime import timedelta

import numpy as np
import pandas as pd
import math
import itertools

from datetime import datetime, timedelta
from pytz import utc
UTCMIN = datetime.min.replace(tzinfo=utc)

class Alpha_Composite:
    def __init__(self, variables, *args, **kwargs):
        
        self.ACR_assets = [
                        "VOE",
                        "VDC",
                        "XLP",
                        "IJR",
                        ]
        self.ACR_bonds = [
                        "TLT",
                        "TIP",
                        "DBC",
                        "SHY",
                        ]
        self.ACR_sectors = [
                            "XLB", #Materials
                            "XLY", #Consumer Cyclical
                            "XLF", #Financials
                            "IYR", #ISHARES Real Estate
                            "XLP", #Consumer Defensive
                            "XLV", #Healthcare
                            "XLU", #Utilities
                            "XLE", #Energy
                            "XLI", #Industrials
                            "XLK", #Tech
                            ]
        
        self.ACR_fixed = [
                        "SPY",
                        ]
        #self.Hedge = ["VXX",]
            
        self.ACR_stocks = self.ACR_assets+self.ACR_bonds+self.ACR_fixed# + self.Hedge
        
        """
        ACR (Asset Class Rotation) parameters
        """
        self.ACR_sector_step = 13 #12% step change = all bonds if 9 of 11 sectors down
        self.ACR_asset_step = 20 #20% step change
        self.ACR_allocation = {}
        self.ACR_fixed_weight = [
                                0.0, #SPY
                                ]
        
        self.ACR_stocks = self.ACR_assets+self.ACR_bonds+self.ACR_fixed# + self.Hedge
        
        #Variable Definitions
        self.resolution = Resolution.Daily
        self.rebalancingTime = UTCMIN
        
        self.days_predicted = 5
        self.rebalancingPeriod = Extensions.ToTimeSpan(self.resolution)*self.days_predicted
        
        self.var = variables
        
        #for stock in self.ACR_sectors:
        #self.var.AddEquity(stock)
        self.symbolData = {}
        
        for symbol in self.ACR_stocks:
                self.ACR_allocation[symbol] = 0.0
                
        """
        VAA parameters
        """
        self.periods = [42,21,63,126,252]
        self.weights = [0, 12, 6,  3, 1]
        
        self.GrowthSymbols = [
                            "SPY",      #SPDR S&P 500 Trust ETF
                            "VEA",      #Vanguard FTSE Developed Markets ETF
                            "VTI",      #Vanguard Total Stock Market ETF
                            "VT",       #Vanguard Total World Stock Index Fund
                            "VWO",      #Vanguard FTSE Emerging Markets ETF
                            "AGG",      #iShares Barclays Aggregate Bond ETF
                            ]
        
        self.SafetySymbols = [
                            "HYD",      #VanEck Vectors High-Yield Municipal ETF
                            "VMBS",     #Vanguard Mortgage-Backed Securities ETF
                            "BKLN",     #Invesco Senior Loan ETF
                            "JNK",      #SPDR Barclays High Yield Bond ETF
                            "TLT",      #iShares 20+ Year Treasury Bond ETF
                            ]
        
        #Variable Definitions
        self.symbolDataBySymbol = {}
        
        self.VAA_allocation = {}
        self.VAA_stocks = self.GrowthSymbols + self.SafetySymbols
        
        for symbol in self.VAA_stocks:
                self.VAA_allocation[symbol] = 0.0  
                
        '''
        Zscore
        '''
        
        #zscore assets
        self.ZScore_stocks = [
                    "SPY",
                    "TLT",
                    "XLP",
                    #"ZIV",
                    ]
        """
        zscore parameters
        """
        self.fixed_wt_pct = 0.0 #.50
        self.fixed_wt = {
                            "XLP": 0.50,
                            "TLT": 0.40, 
                            #"ZIV": 0.10,
                            }
        self.vol_factor = 0.50 #TLT = .5, SPY = 1
        self.ext_factor = 4.0 #move too extreme, leave asset
        self.lookback = 150
        self.ZScore_allocation = {}
        
        
        
        self.stocks = self.ZScore_stocks + self.VAA_stocks + self.ACR_stocks
        
        self.stocks = (list(set(self.stocks)))
        
        for symbol in self.ZScore_stocks:
            self.ZScore_allocation[symbol] = 0.0
        
    def Update(self, algorithm, data):
        #algorithm.Debug("Updating Alpha Model.")
        insights = []
        collect_insights = {}
        
        for stock in self.stocks:
            collect_insights[stock] = {}
        
        if (algorithm.UtcTime <= self.rebalancingTime):
            return insights
        
        for sid in self.ACR_stocks:
            if not sid in self.ACR_allocation:
                self.ACR_allocation[sid] = 0.0
        
        ACR_assets_weight = np.zeros(len(self.ACR_assets))
        ACR_bonds_data = pd.DataFrame(0, columns=['Weight','Ratio','20Day','60Day'],index=self.ACR_bonds) 
        ACR_sectors_data = pd.DataFrame(0, columns=['Ratio','20Day','200Day'],index=self.ACR_sectors)
        """
        Determine sector trends and calculate weight to assets/bonds
        """
        ACR_sectors_data.loc[:,'20Day'] = algorithm.History(self.ACR_sectors, 20, Resolution.Daily)["close"].unstack(level=0).mean()
        ACR_sectors_data.loc[:, '200Day'] = algorithm.History(self.ACR_sectors, 200, Resolution.Daily)["close"].unstack(level=0).mean()
        ACR_sectors_data['Ratio'] = ACR_sectors_data['20Day']/ACR_sectors_data['200Day'] - 1
        
        ACR_bonds_weight = len(ACR_sectors_data[ACR_sectors_data['Ratio'] < 0]) * self.ACR_sector_step/100.0
        if ACR_bonds_weight > 1.0:
            ACR_bonds_weight = 1.0
        ACR_bonds_weight = ACR_bonds_weight * (1-sum(self.ACR_fixed_weight))
        
        """
        Determine bond trends and which duration to be in
        """
        if ACR_bonds_weight > 0.0:
            ACR_bonds_data.loc[:,'20Day'] = algorithm.History(self.ACR_bonds, 20, Resolution.Daily)["close"].unstack(level=0).mean()
            ACR_bonds_data.loc[:, '60Day'] = algorithm.History(self.ACR_bonds, 60, Resolution.Daily)["close"].unstack(level=0).mean()
            ACR_bonds_data['Ratio'] = ACR_bonds_data['20Day']/ACR_bonds_data['60Day'] - 1
            ACR_bonds_data['Weight'] = 0
            ACR_bonds_data.loc[ACR_bonds_data['Ratio'].idxmax(), 'Weight'] = ACR_bonds_weight
        #log.info(self.ACR_bonds_data)
        
        returns = algorithm.History(self.ACR_assets, 126, Resolution.Daily)["close"].unstack(level=0).dropna().pct_change().dropna() + 1.0
        
        expected = algorithm.History(self.ACR_stocks, 20, Resolution.Daily)["close"].unstack(level=0).dropna().pct_change().dropna().mean() + 1.0
        
        """
        Create portfolio combinations
        """
        n = len(self.ACR_assets)
        steps = [x/100.0 for x in range(0,101,int(self.ACR_asset_step))]
        a = [steps for x in range(n)]
        b = list(itertools.product(*a))
        x = [sum(i) for i in b]
        port = pd.DataFrame(b)
        port['Sum'] = x
        port = port[port.Sum == 1]
        del port['Sum']
        """
        Score and Weight portoflio
        """
        port_returns = pd.DataFrame(np.dot(returns, port.T), index=returns.index)
        port_metrics = self.ACR_get_specs(port_returns)
        
        port_metrics = self.ACR_score(port_metrics)
        
        port_metrics['Z3'] = port_metrics.ZMean\
        -port_metrics.ZSTD\
        -port_metrics.ZDownSide\
        +port_metrics.ZAnnualized\
        -port_metrics.ZMax_Draw\
        -port_metrics.ZSTD10\
        +port_metrics.ZMean10\
        +port_metrics.ZMinimum15 
        
        
        port_metrics = port_metrics.sort_values(by='Z3', ascending=False)
        
        portfolios = port
        portfolios.columns = list(returns.columns.values)
        best = pd.concat([pd.DataFrame(portfolios.iloc[port_metrics['Z3'].idxmax()]).T])
        #log.info(best.loc[:, (best != 0).any(axis=0)].T)
        best = pd.DataFrame(portfolios.iloc[port_metrics['Z3'].idxmax()])
        #log.info(best)
        ACR_assets_weight = [i[0]*(1-ACR_bonds_weight-sum(self.ACR_fixed_weight)) for i in best.values]
        
        predictionInterval = Time.Multiply(Extensions.ToTimeSpan(self.resolution), self.days_predicted)
        
        allocation_temp = {}
        magnitude = {}
        direction = {}
        risk_weight = 0
        for x in range(n):
            allocation_temp[self.ACR_assets[x]] = ACR_assets_weight[x]#*.95
            #expected_temp[self.ACR_assets[x]] = 
            risk_weight += ACR_assets_weight[x]
        
        for stock in self.ACR_stocks:
            magnitude[stock] = ((expected[stock]**self.days_predicted)-1.0)/5.0
            #magnitude[stock] = 0.001
            
            #algorithm.Debug(str(stock) + " magnitude = " + str(magnitude[stock]))
            
            if magnitude[stock] > -0.01:
                direction[stock] = InsightDirection.Up
            else:
                direction[stock] = InsightDirection.Flat
                
            magnitude[stock] = 0.001
        
        #self.ACR_allocation[self.Hedge[0]] = risk_weight * .05
        
        for stock in self.ACR_bonds:
            allocation_temp[stock] = ACR_bonds_data.loc[stock, 'Weight']
        for x in range(len(self.ACR_fixed)):
            allocation_temp[self.ACR_fixed[x]] = self.ACR_fixed_weight[x]
        
        for symbol in self.ACR_allocation:
            if (self.ACR_allocation[symbol] != allocation_temp[symbol]) or (self.ACR_allocation[symbol] != 0.0) or (allocation_temp[symbol] != 0.0):
                #if allocation_temp[symbol] > self.ACR_allocation[symbol]:
                self.ACR_allocation[symbol] = allocation_temp[symbol]
                #insights.append(Insight(symbol, predictionInterval, InsightType.Price, InsightDirection.Up, magnitude[symbol], self.ACR_allocation[symbol], sourceModel="Test"))
                collect_insights[symbol]["ACR"] = [predictionInterval, InsightType.Price, InsightDirection.Up, magnitude[symbol], self.ACR_allocation[symbol]]
                #algorithm.Debug(str(symbol) + " = " + str(self.ACR_allocation[symbol]))
                
        
        '''
        VAA
        '''
        
        ##Using a weighted average, compute the score for each risky asset.
        growthdata = []
        for symbol in self.GrowthSymbols:
            if not symbol in self.symbolDataBySymbol.keys(): continue
            temp_values = []
            for i, period in enumerate(self.periods):
                if self.symbolDataBySymbol[symbol][i].CanEmit:
                    temp_values.append(self.symbolDataBySymbol[symbol][i].Return)
                else:
                    temp_values.append(0.0)
                    
            score = sum([i*j for i,j in zip(temp_values,self.weights)])
            growthdata.append([symbol, score, temp_values[0]])
            
        orderedGrowthScores = sorted(growthdata, key=lambda x: x[1], reverse=True)
        #algorithm.Debug(orderedGrowthScores)
        ##Using a weighted average, compute the score for each risk-free asset.
        ##This approach overweights the front month momentum value and progressively underweights older momentum values
        safetydata = []
        for symbol in self.SafetySymbols:
            #self.var.Debug(symbol)
            #self.var.Debug(self.symbolDataBySymbol.keys())
            
            if not symbol in self.symbolDataBySymbol.keys(): continue
            #self.var.Debug("2")
            temp_values = []
            for i, period in enumerate(self.periods):
                #self.var.Debug("3")
                if self.symbolDataBySymbol[symbol][i].CanEmit:
                    #self.var.Debug("4")
                    temp_values.append(self.symbolDataBySymbol[symbol][i].Return)
                else:
                    temp_values.append(0.0)
                    #self.var.Debug("5")
                    
            #score = np.average(temp_values, weights = self.weights)
            score = sum([i*j for i,j in zip(temp_values,self.weights)])
            safetydata.append([symbol, score, temp_values[0]])
        
        orderedSafeScores = sorted(safetydata, key=lambda x: x[1], reverse=True)
        #algorithm.Debug(orderedSafeScores)
        ##Count the number of risky assets with negative momentum scores and store in N. If all four of the offensive assets exhibit positive momentum scores, 
        ##select the offensive asset with the highest score and allocate 100% of the portfolio to that asset at the close
        count = 0
        negative_flag = False
        for stock in orderedGrowthScores:
            if stock[1] <= 0.0:
                count += 1
        if count > 0:
            negative_flag = True
        
        top_growth = orderedGrowthScores[0][0]
        second_growth = orderedGrowthScores[1][0]
        
        top_safe = orderedSafeScores[0][0]
        second_safe = orderedSafeScores[1][0]
        
        predictionInterval = Time.Multiply(Extensions.ToTimeSpan(Resolution.Daily), self.days_predicted)
        
        stock_data = {}
        
        for data in (orderedGrowthScores + orderedSafeScores):
            #stock_data[stock] = [score, momentum, magnitude, direction]
            score = data[1]
            if score == 0.0:
                #DATA ERROR
                continue
            momentum = data[2]
            magnitude = (data[2]/100*(self.days_predicted/self.periods[0]))
            
            if magnitude > -.005:
                direction = InsightDirection.Up
            #elif magnitude < -.005:
                #direction = InsightDirection.Down
            else:
                direction = InsightDirection.Flat
                
            stock_data[data[0]] = [score, momentum, magnitude, direction]
        
                
        for symbol in stock_data:
            weight = 0
            if symbol == top_growth:
                if negative_flag:
                    weight = 0.1
                else:
                    weight = 0.5
            elif symbol == second_growth:
                if negative_flag:
                    weight = 0.1
                else:
                    weight = 0.5
                    
            elif symbol == top_safe:
                if negative_flag:
                    weight = 0.4
                else:
                    weight = 0.0
            elif symbol == second_safe:
                if negative_flag:
                    weight = 0.4
                else:
                    weight = 0.0
            else:
                weight = 0
            
            if self.VAA_allocation[symbol] != weight:
                #insights.append(Insight(symbol, predictionInterval, InsightType.Price, stock_data[symbol][3], stock_data[symbol][2], weight, sourceModel="Test"))
                collect_insights[symbol]["VAA"] = [predictionInterval, InsightType.Price, stock_data[symbol][3], stock_data[symbol][2], weight]
                self.VAA_allocation[symbol] = weight
        
        '''
        ZScore
        '''
        
        safestock = "TLT"   
            
        history = algorithm.History([safestock], self.lookback, Resolution.Daily)
        mean = history['close'].mean()
        sigma = history['close'].std()
        price = float(algorithm.Securities[safestock].Price)
        
        if sigma != 0.0:
            z = (price - mean) / sigma**self.vol_factor
        else:
            z = 0.0
        
        if -self.ext_factor <= z <= self.ext_factor:
            tlt_target = 1.0/(1+math.exp(-1.2*z)) # Pure momentum adding 1 to the sin wave to prevent shorting
        else:
            tlt_target = 0.0
            
        spy_target = (1.0-tlt_target)
        
        allocation_temp = {}
        magnitude = {}
        direction = {}
        
        for sid in self.ZScore_stocks:
            allocation_temp[sid] = 0.0
            if sid in self.fixed_wt:
                allocation_temp[sid] = self.fixed_wt[sid] * self.fixed_wt_pct
        
        allocation_temp[safestock] += tlt_target * (1.0 - self.fixed_wt_pct)
        allocation_temp["SPY"] += spy_target * (1.0 - self.fixed_wt_pct)
        
        
        predictionInterval = Time.Multiply(Extensions.ToTimeSpan(self.resolution), self.days_predicted)
        
        expected = algorithm.History(self.ZScore_stocks, 5, Resolution.Daily)["close"].unstack(level=0).dropna().pct_change().dropna().mean() + 1.0
        
        for stock in self.ZScore_stocks:
            magnitude[stock] = ((expected[stock]**self.days_predicted)-1.0)/2.0
            
            if magnitude[stock] > -0.005:
                direction[stock] = InsightDirection.Up
            else:
                direction[stock] = InsightDirection.Flat
        
        for symbol in self.ZScore_allocation:
            if (self.ZScore_allocation[symbol] != allocation_temp[symbol]) or (self.ZScore_allocation[symbol] != 0.0) or (allocation_temp[symbol] != 0.0):
                self.ZScore_allocation[symbol] = allocation_temp[symbol]
                #insights.append(Insight(symbol, predictionInterval, InsightType.Price, direction[symbol], magnitude[symbol], self.ZScore_allocation[symbol], sourceModel="Test"))
                collect_insights[symbol]["ZScore"] = [predictionInterval, InsightType.Price, direction[symbol], magnitude[symbol], self.ZScore_allocation[symbol]]
                #algorithm.Debug(str(symbol) + " = " + str(self.ZScore_allocation[symbol]))
                
                
        '''
        combined
        '''
        
        for symbol in self.stocks:
            num_alphas = 3.0
            magnitude = 0.0
            allocation = 0.0
            direction = InsightDirection.Flat
            if collect_insights[symbol] != {}:
                for alpha in collect_insights[symbol].keys():
                    allocation += collect_insights[symbol][alpha][4]/num_alphas
                    magnitude += collect_insights[symbol][alpha][3]/num_alphas
                
                if magnitude > -0.005:
                    direction = InsightDirection.Up
                else:
                    direction = InsightDirection.Flat
                    
                insights.append(Insight(symbol, predictionInterval, InsightType.Price, direction, magnitude, allocation))
        
        
        self.rebalancingTime = algorithm.UtcTime + self.rebalancingPeriod
        
        return Insight.Group( insights )        
        
    def ACR_drawdown(self, returns):
        mat = returns.cumprod().values
        [n, m] = np.shape(mat)
        maxes = np.maximum.accumulate(np.array(mat))
        for i in range(0,n):
            for j in range(m):
                mat[i,j] = mat[i,j] / maxes[i,j]
        df = pd.DataFrame(mat)
        df[df > 1] = 1
        return df
        
    def ACR_moving_returns(self, returns, w):
        mat = returns.values
        [n, m] = np.shape(mat)
        ret = np.zeros(shape = (n-w+1,m))
        for i in range(w-1,n):
            for j in range(m):
                ret[i-w+1,j] = np.power(np.prod(mat[(i-w+1):i+1,j]),(1.0/w))- 1.0
        return pd.DataFrame(ret)
        
    def ACR_get_specs(self, returns):
        metrics = pd.DataFrame((returns.mean()),columns=['Mean']) - 1.0
        metrics['STD'] = pd.DataFrame((returns.std()))
        metrics['Annualized'] = np.power(returns.cumprod().values.tolist()[-1],1.0/len(returns))- 1.0
        
        downside = returns.copy(deep=True) - 1
        downside[downside > 0] = 0
        downside = downside ** 2
        metrics['DownSide'] = pd.DataFrame(downside.mean() ** 0.5)
        
        draw = self.ACR_drawdown(returns)
        metrics['Max_Draw'] = 1.0 - draw.min().values
        ret15 = self.ACR_moving_returns(returns,21)
        metrics['Minimum15'] = ret15.min().values
        
        ret10 = self.ACR_moving_returns(returns,21)
        metrics['Mean10'] = ret10.mean().values
        metrics['STD10'] = ret10.std().values
        
        return metrics
        
    def ACR_zscore(self, stocks, var, var_save):
        stocks[var_save] = (stocks[var] - stocks[var].mean())/stocks[var].std(ddof=0)
        return stocks 
        
    def ACR_score(self, metrics):
        metrics = self.ACR_zscore(metrics, 'Mean', 'ZMean')
        metrics = self.ACR_zscore(metrics, 'STD', 'ZSTD')
        metrics = self.ACR_zscore(metrics, 'Annualized', 'ZAnnualized')
        metrics = self.ACR_zscore(metrics, 'DownSide', 'ZDownSide')
        metrics = self.ACR_zscore(metrics, 'Max_Draw', 'ZMax_Draw')
        metrics = self.ACR_zscore(metrics, 'Minimum15', 'ZMinimum15')
        metrics = self.ACR_zscore(metrics, 'STD10', 'ZSTD10')
        metrics = self.ACR_zscore(metrics, 'Mean10', 'ZMean10')
        return metrics
            
    def OnSecuritiesChanged(self, algorithm, changes):
        algorithm.Debug("Securities Changed. Added " + str(changes.AddedSecurities))
        symbols = [ x.Symbol for x in changes.AddedSecurities if str(x.Symbol) in self.VAA_stocks ]
        history = algorithm.History(symbols, (np.max(self.periods)), Resolution.Daily)
        if history.empty:
            algorithm.Debug("History Error")
            return
    
        for removed in changes.RemovedSecurities:
            if removed.Symbol in self.VAA_stocks:
                symbolData_temp = self.symbolDataBySymbol.pop(removed.Symbol, None)
                if symbolData_temp is not None:
                    symbolData_temp.RemoveConsolidators(algorithm)
                    
        for stock in history.index.levels[0]:
            symbol = SymbolCache.GetSymbol(stock)
            algorithm.Debug("Getting Data for " + str(symbol))
            if str(symbol) not in self.symbolDataBySymbol.keys():
                algorithm.Debug("registering symboldata for " + str(symbol))
                symbolData_temp = []
                
                for period in self.periods:
                    #algorithm.Debug("C")
                    tempData = SymbolData(symbol, period)
                    
                    tempData.RegisterIndicators(algorithm, Resolution.Daily)
                    tempData.WarmUpIndicators(history.loc[stock])
                    
                    symbolData_temp.append(tempData)
                
                self.symbolDataBySymbol[str(symbol)] = symbolData_temp
                #algorithm.Debug(symbolData_temp)
                    

class SymbolData:
    def __init__(self, symbol, lookback):
        self.Symbol = symbol
        self.MOM = Momentum('{}.MOM({})'.format(symbol, lookback), lookback)
        self.Consolidator = None
        self.previous = 0
    
    def RegisterIndicators(self, algorithm, resolution):
        #algorithm.Debug("Register Indicators. Alpha")
        self.Consolidator = algorithm.ResolveConsolidator(self.Symbol, resolution)
        algorithm.RegisterIndicator(self.Symbol, self.MOM, self.Consolidator)
    
    def RemoveConsolidators(self, algorithm):
        if self.Consolidator is not None:
            algorithm.SubscriptionManager.RemoveConsolidator(self.Symbol, self.Consolidator)
    
    def WarmUpIndicators(self, history):
        for tuple in history.itertuples():
            self.MOM.Update(tuple.Index, tuple.close)
    
    @property
    def Return(self):
        return float(self.MOM.Current.Value)
    
    @property
    def CanEmit(self):
        if self.previous == self.MOM.Samples:
            return False
        
        self.previous = self.MOM.Samples
        return self.MOM.IsReady
'''
    def __str__(self, **kwargs):
        return '{}: {:.2%}'.format(self.MOM.Name, (1 + self.Return)**252 - 1)
'''
# QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
# Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from clr import AddReference
AddReference("System")
AddReference("QuantConnect.Common")
AddReference("QuantConnect.Algorithm.Framework")

from QuantConnect.Algorithm.Framework.Portfolio import PortfolioTarget
from QuantConnect.Algorithm.Framework.Risk import RiskManagementModel
from QuantConnect.Algorithm.Framework.Alphas import InsightCollection

from datetime import datetime
from pytz import utc
UTCMIN = datetime.min.replace(tzinfo=utc)

class Drawdown_Risk_Model(RiskManagementModel):
    
    def __init__(self, max_drawdown = 0.025, security_stop = .025, multi_day_slide_stop = .025, wait_days = 5):
        
        self.insightCollection = InsightCollection()
        
        self.rebalancingTime = UTCMIN
        self.rebalancingPeriod = Extensions.ToTimeSpan(Resolution.Daily)
        
        self.max_drawdown = -abs(max_drawdown)
        self.sec_stop = -abs(security_stop)
        self.multi_day_slide_stop = -abs(multi_day_slide_stop)
        
        self.wait_days = int(wait_days)
        self.blacklist = {}
        
        
        self.ago_portfolio = .0001
        self.yesterday_portfolio = .0001
        self.today_portfolio = .0001
        self.max_portfolio = .0001
        
        self.waited_days = 0
        self.port_liquidate = False

    def ManageRisk(self, algorithm, targets):
        
        targets = []
        
        if algorithm.UtcTime > self.rebalancingTime:
            self.ago_portfolio = self.yesterday_portfolio
            self.yesterday_portfolio = self.today_portfolio
            self.today_portfolio = float(algorithm.Portfolio.TotalPortfolioValue)
            
            self.max_portfolio = max(self.max_portfolio, self.today_portfolio)
            
            for symbol in self.blacklist:
                self.blacklist[symbol] +=1
                
            if self.port_liquidate:
                algorithm.Debug("Portfolio drop stop! Wait " + str(self.wait_days) + ". " + str(algorithm.UtcTime))
                self.waited_days += 1
                if self.waited_days > self.wait_days:
                    self.port_liquidate = False
                    self.waited_days = 0
                
            self.rebalancingTime = algorithm.UtcTime + self.rebalancingPeriod
            
        current_portfolio = float(algorithm.Portfolio.TotalPortfolioValue)
        
        if ((current_portfolio/self.max_portfolio)-1.0) < self.max_drawdown:
            self.max_portfolio = current_portfolio
            self.port_liquidate = True
            algorithm.Debug("Max drop stop! Wait " + str(self.wait_days) + ". " + str(algorithm.UtcTime))
            
        if (((current_portfolio/self.ago_portfolio)-1.0) < self.multi_day_slide_stop) or (((current_portfolio/self.yesterday_portfolio)-1.0) < self.multi_day_slide_stop) or self.port_liquidate:
            self.port_liquidate = True
            
            for kvp in algorithm.Securities:
                security = kvp.Value
                if security.Invested:
                    self.insightCollection.Clear([security.Symbol])
                    targets.append(PortfolioTarget(security.Symbol, 0))
        
        for kvp in algorithm.Securities:
            security = kvp.Value
            liquidate = False
            pnl = 0.0

            if security.Invested:
                pnl = security.Holdings.UnrealizedProfitPercent
                if pnl < self.sec_stop:
                    liquidate = True
                    
            if security.Symbol in self.blacklist:
                if self.blacklist[security.Symbol] > self.wait_days:
                    self.blacklist.pop(security.Symbol, None)
                else:
                    liquidate = True
            elif liquidate:
                algorithm.Debug("Stop on " + str(security.Symbol) + "! Wait " + str(self.wait_days) + ". " + str(algorithm.UtcTime))
                self.blacklist[security.Symbol] = 0
            if liquidate:
                self.insightCollection.Clear([security.Symbol])
                targets.append(PortfolioTarget(security.Symbol, 0))
        
        
        return targets
from clr import AddReference
AddReference("QuantConnect.Algorithm.Framework")
AddReference("QuantConnect.Indicators")
AddReference("QuantConnect.Common")

from QuantConnect import *
from QuantConnect.Indicators import *
from QuantConnect.Algorithm.Framework.Alphas import *

from Utility_Functions import *
from datetime import timedelta

import numpy as np
import pandas as pd
import itertools

from datetime import datetime, timedelta
from pytz import utc
UTCMIN = datetime.min.replace(tzinfo=utc)

class Alpha_ACR:
    def __init__(self, variables, *args, **kwargs):
        
        """
        ACR (Asset Class Rotation) parameters
        """
        self.ACR_sector_step = 13 #12% step change = all bonds if 9 of 11 sectors down
        self.ACR_asset_step = 20 #20% step change
        self.allocation = {}
        self.ACR_fixed_weight = [
                                0.0, #SPY
                                ]
                                
        self.ACR_assets = [
                        "VOE",
                        "VDC",
                        "XLP",
                        "IJR",
                        ]
        self.ACR_bonds = [
                        "TLT",
                        "TIP",
                        "DBC",
                        "SHY",
                        ]
        self.ACR_sectors = [
                            "XLB", #Materials
                            "XLY", #Consumer Cyclical
                            "XLF", #Financials
                            "IYR", #ISHARES Real Estate
                            "XLP", #Consumer Defensive
                            "XLV", #Healthcare
                            "XLU", #Utilities
                            "XLE", #Energy
                            "XLI", #Industrials
                            "XLK", #Tech
                            ]
        
        self.ACR_fixed = [
                        "SPY",
                        ]
        #self.Hedge = ["VXX",]
        
        self.stocks = self.ACR_assets+self.ACR_bonds+self.ACR_fixed# + self.Hedge
        
        #Variable Definitions
        self.resolution = Resolution.Daily
        self.rebalancingTime = UTCMIN
        
        self.days_predicted = 5
        self.rebalancingPeriod = Extensions.ToTimeSpan(self.resolution)*self.days_predicted
        
        self.var = variables
        
        #for stock in self.ACR_sectors:
        #self.var.AddEquity(stock)
        self.symbolData = {}
        
        for symbol in self.stocks:
                self.allocation[symbol] = 0.0
        
    def Update(self, algorithm, data):
        #algorithm.Debug("Updating Alpha Model.")
        insights = []
        
        if (algorithm.UtcTime <= self.rebalancingTime):
            return insights
        
        self.symbolData["sectors20"] = algorithm.History(self.ACR_sectors, 20, Resolution.Daily)["close"]
        self.symbolData["sectors200"] = algorithm.History(self.ACR_sectors, 200, Resolution.Daily)["close"]
        self.symbolData["bonds20"] = algorithm.History(self.ACR_bonds, 20, Resolution.Daily)["close"]
        self.symbolData["bonds60"] = algorithm.History(self.ACR_bonds, 60, Resolution.Daily)["close"]
        self.symbolData["assets126"] = algorithm.History(self.ACR_assets, 126, Resolution.Daily)["close"]
        self.symbolData["return5"] = algorithm.History(self.stocks, 5, Resolution.Daily)["close"]
        
        
        ACR_assets_weight = np.zeros(len(self.ACR_assets))
        ACR_bonds_data = pd.DataFrame(0, columns=['Weight','Ratio','20Day','60Day'],index=self.ACR_bonds) 
        ACR_sectors_data = pd.DataFrame(0, columns=['Ratio','20Day','200Day'],index=self.ACR_sectors)
        """
        Determine sector trends and calculate weight to assets/bonds
        """
        ACR_sectors_data.loc[:,'20Day'] = self.symbolData["sectors20"].unstack(level=0).mean()
        ACR_sectors_data.loc[:, '200Day'] = self.symbolData["sectors200"].unstack(level=0).mean()
        ACR_sectors_data['Ratio'] = ACR_sectors_data['20Day']/ACR_sectors_data['200Day'] - 1
        
        ACR_bonds_weight = len(ACR_sectors_data[ACR_sectors_data['Ratio'] < 0]) * self.ACR_sector_step/100.0
        if ACR_bonds_weight > 1.0:
            ACR_bonds_weight = 1.0
        ACR_bonds_weight = ACR_bonds_weight * (1-sum(self.ACR_fixed_weight))
        
        """
        Determine bond trends and which duration to be in
        """
        if ACR_bonds_weight > 0.0:
            ACR_bonds_data.loc[:,'20Day'] = self.symbolData["bonds20"].unstack(level=0).mean()
            ACR_bonds_data.loc[:, '60Day'] = self.symbolData["bonds60"].unstack(level=0).mean()
            ACR_bonds_data['Ratio'] = ACR_bonds_data['20Day']/ACR_bonds_data['60Day'] - 1
            ACR_bonds_data['Weight'] = 0
            ACR_bonds_data.loc[ACR_bonds_data['Ratio'].idxmax(), 'Weight'] = ACR_bonds_weight
        #log.info(self.ACR_bonds_data)
        
        returns = self.symbolData["assets126"].unstack(level=0).dropna().pct_change().dropna() + 1.0
        
        expected = self.symbolData["return5"].unstack(level=0).dropna().pct_change().dropna().mean() + 1.0
        #algorithm.Debug(expected)
        """
        Create portfolio combinations
        """
        n = len(self.ACR_assets)
        steps = [x/100.0 for x in range(0,101,int(self.ACR_asset_step))]
        a = [steps for x in range(n)]
        b = list(itertools.product(*a))
        x = [sum(i) for i in b]
        port = pd.DataFrame(b)
        port['Sum'] = x
        port = port[port.Sum == 1]
        del port['Sum']
        """
        Score and Weight portoflio
        """
        port_returns = pd.DataFrame(np.dot(returns, port.T), index=returns.index)
        port_metrics = self.ACR_get_specs(port_returns)
        
        
        port_metrics = self.ACR_score(port_metrics)
        
        port_metrics['Z3'] = port_metrics.ZMean\
        -port_metrics.ZSTD\
        -port_metrics.ZDownSide\
        +port_metrics.ZAnnualized\
        -port_metrics.ZMax_Draw\
        -port_metrics.ZSTD10\
        +port_metrics.ZMean10\
        +port_metrics.ZMinimum15
        
        port_metrics = port_metrics.sort_values(by='Z3', ascending=False)
        
        portfolios = port
        portfolios.columns = list(returns.columns.values)
        best = pd.concat([pd.DataFrame(portfolios.iloc[port_metrics['Z3'].idxmax()]).T])
        #log.info(best.loc[:, (best != 0).any(axis=0)].T)
        
        best = pd.DataFrame(portfolios.iloc[port_metrics['Z3'].idxmax()])
        #log.info(best)
        ACR_assets_weight = [i[0]*(1-ACR_bonds_weight-sum(self.ACR_fixed_weight)) for i in best.values]
        
        allocation_temp = {}
        magnitude = {}
        direction = {}
        risk_weight = 0
        for x in range(n):
            allocation_temp[self.ACR_assets[x]] = ACR_assets_weight[x]#*.95
            #expected_temp[self.ACR_assets[x]] = 
            risk_weight += ACR_assets_weight[x]
        
        predictionInterval = Time.Multiply(Extensions.ToTimeSpan(self.resolution), self.days_predicted)
        
        for stock in self.stocks:
            magnitude[stock] = ((expected[stock]**self.days_predicted)-1.0)
            
            if magnitude[stock] > 0.0:
                direction[stock] = InsightDirection.Up
            elif magnitude[stock] < 0.0:
                direction[stock] = InsightDirection.Down
            else:
                direction[stock] = InsightDirection.Flat
        
        #self.allocation[self.Hedge[0]] = risk_weight * .05
        
        for stock in self.ACR_bonds:
            allocation_temp[stock] = ACR_bonds_data.loc[stock, 'Weight']
        for x in range(len(self.ACR_fixed)):
            allocation_temp[self.ACR_fixed[x]] = self.ACR_fixed_weight[x]
        
        for symbol in self.allocation:
            if (self.allocation[symbol] != allocation_temp[symbol]) or (self.allocation[symbol] != 0.0) or (allocation_temp[symbol] != 0.0):
                self.allocation[symbol] = allocation_temp[symbol]
                insights.append(Insight(symbol, predictionInterval, InsightType.Price, direction[symbol], magnitude[symbol], self.allocation[symbol], sourceModel="Test"))
                #algorithm.Debug(str(symbol) + " = " + str(self.allocation[symbol]))
        
        #insights = [] #Remove me
        
        #return insights
        self.rebalancingTime = algorithm.UtcTime + self.rebalancingPeriod
        
        return Insight.Group( insights )
        
    def ACR_drawdown(self, returns):
        mat = returns.cumprod().values
        [n, m] = np.shape(mat)
        maxes = np.maximum.accumulate(np.array(mat))
        for i in range(0,n):
            for j in range(m):
                mat[i,j] = mat[i,j] / maxes[i,j]
        df = pd.DataFrame(mat)
        df[df > 1] = 1
        return df
        
    def ACR_moving_returns(self, returns, w):
        mat = returns.values
        [n, m] = np.shape(mat)
        ret = np.zeros(shape = (n-w+1,m))
        for i in range(w-1,n):
            for j in range(m):
                ret[i-w+1,j] = np.power(np.prod(mat[(i-w+1):i+1,j]),(1.0/w))- 1.0
        return pd.DataFrame(ret)
        
    def ACR_get_specs(self, returns):
        metrics = pd.DataFrame((returns.mean()),columns=['Mean']) - 1.0
        metrics['STD'] = pd.DataFrame((returns.std()))
        metrics['Annualized'] = np.power(returns.cumprod().values.tolist()[-1],1.0/len(returns))- 1.0
        
        downside = returns.copy(deep=True) - 1
        downside[downside > 0] = 0
        downside = downside ** 2
        metrics['DownSide'] = pd.DataFrame(downside.mean() ** 0.5)
        
        draw = self.ACR_drawdown(returns)
        metrics['Max_Draw'] = 1.0 - draw.min().values
        ret15 = self.ACR_moving_returns(returns,21)#21
        metrics['Minimum15'] = ret15.min().values
        
        ret10 = self.ACR_moving_returns(returns,21)#21
        metrics['Mean10'] = ret10.mean().values
        metrics['STD10'] = ret10.std().values
        
        return metrics
        
    def ACR_zscore(self, stocks, var, var_save):
        stocks[var_save] = (stocks[var] - stocks[var].mean())/stocks[var].std(ddof=0)
        return stocks
        
    def ACR_score(self, metrics):
        metrics = self.ACR_zscore(metrics, 'Mean', 'ZMean')
        metrics = self.ACR_zscore(metrics, 'STD', 'ZSTD')
        metrics = self.ACR_zscore(metrics, 'Annualized', 'ZAnnualized')
        metrics = self.ACR_zscore(metrics, 'DownSide', 'ZDownSide')
        metrics = self.ACR_zscore(metrics, 'Max_Draw', 'ZMax_Draw')
        metrics = self.ACR_zscore(metrics, 'Minimum15', 'ZMinimum15')
        metrics = self.ACR_zscore(metrics, 'STD10', 'ZSTD10')
        metrics = self.ACR_zscore(metrics, 'Mean10', 'ZMean10')
        return metrics
            
    def OnSecuritiesChanged(self, algorithm, changes):
        pass
from System import *
from QuantConnect import *
from QuantConnect.Orders import *
from QuantConnect.Algorithm import *
from QuantConnect.Algorithm.Framework import *
from QuantConnect.Algorithm.Framework.Execution import * 
from QuantConnect.Algorithm.Framework.Risk import * 
from QuantConnect.Algorithm.Framework.Selection import *
from QuantConnect.Algorithm.Framework.Alphas import *

from Alpha_VAA import Alpha_VAA
from Alpha_ACR_2 import Alpha_ACR
from Alpha_ZScore import Alpha_ZScore
from Alpha_Composite import Alpha_Composite

from Confidence_Weighted_Portfolio import Confidence_Weighted_Portfolio
from Zero_Leverage_ExecutionModel import Zero_Leverage_ExecutionModel
from Drawdown_Risk_Model import Drawdown_Risk_Model

from Utility_Functions import Utilities
import numpy as np
import pandas as pd
from scipy.optimize import minimize

class Modular_Framework(QCAlgorithmFramework):
    '''Mean Variance Optimization Algorithm.'''

    def Initialize(self):
        """
        General Algorithm Parameters
        """
        self.UniverseSettings.Resolution = Resolution.Minute    #Set Data Resolution
        self.SetStartDate(2008, 1, 1)                           #Set Start Date
        self.SetEndDate(2018, 8, 28)                            #Set End Date
        self.SetCash(100000)                                     #Set Strategy Cash
        self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Margin) #Set Brokerage Model
        self.SetBenchmark("SPY")
        self.SetWarmup(252) #252
        
        """
        Portfolio Construction Parameters
        """
        self.max_leverage                 = 1.0 #highest combined leverage
        self.reserved                     = 0.0 #Tell algo to reserve (won't trade with) this amount of cash
        #self.normalize                    = True #noramalize leverage (attempt to stay at max leverage always)
        
        """
        Portfolio Execution Parameters
        """
        self.Minimum_order_value = 2500 #This reduces fees by trading only when a large reblance is needed
        
        """
        Portfolio Risk Management Parameters
        """
        self.max_drawdown = .04
        self.security_stop = .04
        self.multi_day_slide_stop = .04
        self.wait_days = 5
        
        """
        Universe
        """
        self.assets_VAA = [
                            "SPY",      #SPDR S&P 500 Trust ETF
                            "VEA",      #Vanguard FTSE Developed Markets ETF
                            "VTI",      #Vanguard Total Stock Market ETF
                            "AGG",      #iShares Barclays Aggregate Bond Fund
                            "HYD",      #VanEck Vectors High-Yield Municipal ETF
                            "VMBS",     #Vanguard Mortgage-Backed Securities ETF
                            "BKLN",     #Invesco Senior Loan ETF
                            "JNK",      #SPDR Barclays High Yield Bond ETF
                            "VT",       ##Vanguard Total World Stock Index Fund
                            "VWO",      #Vanguard FTSE Emerging Markets ETF
                            "TLT",      #iShares 20+ Year Treasury Bond ETF
                            ]
                            
        self.assets_ACR = [
                            "VOE",
                            "VDC",
                            "XLP",
                            "IJR",
                            "TLT",
                            "TIP",
                            "DBC",
                            "SHY",
                            "XLB",      #Materials
                            "XLY",      #Consumer Cyclical
                            "XLF",      #Financials
                            "IYR",      #ISHARES Real Estate
                            "XLP",      #Consumer Defensive
                            "XLV",      #Healthcare
                            "XLU",      #Utilities
                            "XLE",      #Energy
                            "XLI",      #Industrials
                            "XLK",      #Tech
                            "SPY",
                            ]
                            
        self.assets_ZScore = [
                            "SPY",
                            "TLT",
                            ]
        
        self.universe = self.assets_VAA + self.assets_ACR + self.assets_ZScore
        
        self.universe = (list(set(self.universe)))
        
        universe = [ Symbol.Create(symbol, SecurityType.Equity, Market.USA) for symbol in self.universe ]
        
        """
        Framework Parameters
        """
        #SET UNIVERSE MODEL
        self.SetUniverseSelection( ManualUniverseSelectionModel(universe) )
        
        #SET ALPHA MODELS
        #self.SetAlpha( Alpha_VAA(self) )
        #self.SetAlpha( Alpha_ACR(self) )
        #self.SetAlpha( Alpha_ZScore(self) )
        #self.SetAlpha( Alpha_Composite(self) )
        alphas = [  
                    #Alpha_VAA(self),
                    #Alpha_ACR(self),
                    Alpha_ZScore(self),
                ]
        self.num_alphas = len(alphas)        
        self.SetAlpha( CompositeAlphaModel(*alphas))
        
        #SET PORTFOLIO CONSTRUCTION MODEL
        self.SetPortfolioConstruction( Confidence_Weighted_Portfolio(Resolution.Daily, self.reserved, self.max_leverage, self.num_alphas, False) )
        
        #SET EXECUTION MODEL
        #self.SetExecution( NullExecutionModel() )
        self.SetExecution( Zero_Leverage_ExecutionModel(Resolution.Daily, self.Minimum_order_value) )
        
        #SET RISK MANAGEMENT MODEL
        self.SetRiskManagement( NullRiskManagementModel() )
        #self.SetRiskManagement( Drawdown_Risk_Model(self.max_drawdown, self.security_stop, self.multi_day_slide_stop, self.wait_days) )
        
        
        """
        Scheduled Functions
        """
        #self.Schedule.On(self.DateRules.Every([DayOfWeek.Monday]),
        self.Schedule.On(self.DateRules.EveryDay(),
                self.TimeRules.At(9, 31),
                Action(self.VAA_Rebal))
        
        """
        Flags - Do not Change these!
        """
        self.VAA_calculated = False
        
    
    def VAA_Rebal(self):
        pass
        #self.VAA_calculated = False
"""
Misc/Utility Functions
"""
import numpy as np

#class Utilities(object):
class Utilities:
    def __init__(self, variables):
        self.var = variables
    
    def Variance(self,x,*args):
        #Variance Function for SLSQP
        p = np.squeeze(np.asarray(args))
        Acov = np.cov(p.T)
        
        return np.dot(x,np.dot(Acov,x))
    
    def Jac_Variance(self,x,*args):
        #jac_variance Function for SLSQP
        p = np.squeeze(np.asarray(args))
        Acov = np.cov(p.T)
        
        return 2*np.dot(Acov,x)
    
    def Unique(self,seq,idfun=None): 
        # order preserving
        if idfun is None:
            def idfun(x): return x
        seen = {}
        result = []
        for item in seq:
            marker = idfun(item)
            if marker in seen:
                continue
            seen[marker] = 1
            result.append(item)
        return result
    
    def my_record_vars(self):
        #self.var.Debug("my_record_vars")
        account_leverage = float(self.var.Portfolio.TotalHoldingsValue) / float(self.var.Portfolio.TotalPortfolioValue)
        self.var.Plot('Leverage', 'Leverage', account_leverage)
        
        portfolio = self.var.Portfolio
        positions = portfolio.Keys
        pos = 0
        short = 0
        
        for symbol in positions:
            if not self.var.Securities.ContainsKey(symbol): continue
            if portfolio[symbol].IsLong:
                pos += 1
            if portfolio[symbol].IsShort:
                short += 1
        self.var.Plot('Data Graph', 'Long', pos)
        self.var.Plot('Data Graph', 'Short', short)
    
    def cancel_open_orders(self):
        #self.var.Debug("cancel_open_orders")
        oo = [order.Symbol for order in self.var.Transactions.GetOpenOrders()]
        if len(oo) == 0: return
        oo = self.Unique(oo)
        for symbol in oo:
            if not self.var.Securities.ContainsKey(symbol): return
            self.var.Transactions.CancelOpenOrders(symbol)
    
    def cancel_open_order(self, symbol):
        #self.var.Debug("cancel_open_order")
        if not self.var.Securities.ContainsKey(symbol): return
        oo = self.var.Transactions.GetOpenOrders(symbol)
        if len(oo) == 0: return
        self.var.Transactions.CancelOpenOrders(symbol)
    
    def get_open_orders(self, symbol=None):
        #self.var.Debug("get_open_orders")
        orders = False
        if symbol == None:
            if len(self.var.Transactions.GetOpenOrders()) > 0:
                orders = True
        else:
            if not self.var.Securities.ContainsKey(symbol):
                return orders
            if len(self.var.Transactions.GetOpenOrders(symbol)) > 0:
                orders = True
        return orders
from clr import AddReference
AddReference("QuantConnect.Algorithm.Framework")
AddReference("QuantConnect.Indicators")
AddReference("QuantConnect.Common")

from QuantConnect import *
from QuantConnect.Indicators import *
from QuantConnect.Algorithm.Framework.Alphas import *

from datetime import datetime, timedelta
from pytz import utc
UTCMIN = datetime.min.replace(tzinfo=utc)

import numpy as np

class Alpha_VAA:
    def __init__(self, variables, *args, **kwargs):
        self.Name = "Alpha_VAA"
        
        """
        VAA parameters
        """
        self.periods = [42,21,63,126,252]
        self.weights = [0, 12, 6,  3, 1]
        
        self.resolution = Resolution.Daily
        self.rebalancingTime = UTCMIN
        
        self.days_predicted = 5
        self.rebalancingPeriod = Extensions.ToTimeSpan(self.resolution)*self.days_predicted
        
        self.GrowthSymbols = [
                            "SPY",      #SPDR S&P 500 Trust ETF
                            "VEA",      #Vanguard FTSE Developed Markets ETF
                            "VTI",      #Vanguard Total Stock Market ETF
                            "VT",       #Vanguard Total World Stock Index Fund
                            "VWO",      #Vanguard FTSE Emerging Markets ETF
                            "AGG",      #iShares Barclays Aggregate Bond ETF
                            ]
        
        self.SafetySymbols = [
                            "HYD",      #VanEck Vectors High-Yield Municipal ETF
                            "VMBS",     #Vanguard Mortgage-Backed Securities ETF
                            "BKLN",     #Invesco Senior Loan ETF
                            "JNK",      #SPDR Barclays High Yield Bond ETF
                            "TLT",      #iShares 20+ Year Treasury Bond ETF
                            ]
        
        #Variable Definitions
        self.symbolDataBySymbol = {}
        self.var = variables
        
        self.VAA_calculated = False
        
        self.allocation = {}
        self.stocks = self.GrowthSymbols + self.SafetySymbols
        
        for symbol in self.stocks:
                self.allocation[symbol] = 0.0
        
    def Update(self, algorithm, data):
        insights = []
        
        
        if (algorithm.UtcTime <= self.rebalancingTime):
            return insights
        
        ##Using a weighted average, compute the score for each risky asset.
        growthdata = []
        for symbol in self.GrowthSymbols:
            if not symbol in self.symbolDataBySymbol.keys(): continue
            temp_values = []
            for i, period in enumerate(self.periods):
                if self.symbolDataBySymbol[symbol][i].CanEmit:
                    temp_values.append(self.symbolDataBySymbol[symbol][i].Return)
                else:
                    temp_values.append(0.0)
                    
            score = sum([i*j for i,j in zip(temp_values,self.weights)])
            growthdata.append([symbol, score, temp_values[0]])
            
        orderedGrowthScores = sorted(growthdata, key=lambda x: x[1], reverse=True)
        #algorithm.Debug(orderedGrowthScores)
        ##Using a weighted average, compute the score for each risk-free asset.
        ##This approach overweights the front month momentum value and progressively underweights older momentum values
        safetydata = []
        for symbol in self.SafetySymbols:
            #self.var.Debug(symbol)
            #self.var.Debug(self.symbolDataBySymbol.keys())
            
            if not symbol in self.symbolDataBySymbol.keys(): continue
            #self.var.Debug("2")
            temp_values = []
            for i, period in enumerate(self.periods):
                #self.var.Debug("3")
                if self.symbolDataBySymbol[symbol][i].CanEmit:
                    #self.var.Debug("4")
                    temp_values.append(self.symbolDataBySymbol[symbol][i].Return)
                else:
                    temp_values.append(0.0)
                    #self.var.Debug("5")
                    
            #score = np.average(temp_values, weights = self.weights)
            score = sum([i*j for i,j in zip(temp_values,self.weights)])
            safetydata.append([symbol, score, temp_values[0]])
        
        orderedSafeScores = sorted(safetydata, key=lambda x: x[1], reverse=True)
        #algorithm.Debug(orderedSafeScores)
        ##Count the number of risky assets with negative momentum scores and store in N. If all four of the offensive assets exhibit positive momentum scores, 
        ##select the offensive asset with the highest score and allocate 100% of the portfolio to that asset at the close
        count = 0
        negative_flag = False
        for stock in orderedGrowthScores:
            if stock[1] <= 0.0:
                count += 1
        if count > 0:
            negative_flag = True
        
        top_growth = orderedGrowthScores[0][0]
        second_growth = orderedGrowthScores[1][0]
        
        top_safe = orderedSafeScores[0][0]
        second_safe = orderedSafeScores[1][0]
        
        predictionInterval = Time.Multiply(Extensions.ToTimeSpan(Resolution.Daily), self.days_predicted)
        
        stock_data = {}
        
        for data in (orderedGrowthScores + orderedSafeScores):
            #stock_data[stock] = [score, momentum, magnitude, direction]
            score = data[1]
            if score == 0.0:
                #DATA ERROR
                continue
            momentum = data[2]
            magnitude = (data[2]/100*(self.days_predicted/self.periods[0]))
            
            if magnitude > -.005:
                direction = InsightDirection.Up
            #elif magnitude < -.005:
                #direction = InsightDirection.Down
            else:
                direction = InsightDirection.Flat
                
            stock_data[data[0]] = [score, momentum, magnitude, direction]
        
                
        for symbol in stock_data:
            weight = 0
            if symbol == top_growth:
                if negative_flag:
                    weight = 0.1
                else:
                    weight = 0.5
            elif symbol == second_growth:
                if negative_flag:
                    weight = 0.1
                else:
                    weight = 0.5
                    
            elif symbol == top_safe:
                if negative_flag:
                    weight = 0.4
                else:
                    weight = 0.0
            elif symbol == second_safe:
                if negative_flag:
                    weight = 0.4
                else:
                    weight = 0.0
            else:
                weight = 0
            
            if self.allocation[symbol] != weight:
                insights.append(Insight(symbol, predictionInterval, InsightType.Price, stock_data[symbol][3], stock_data[symbol][2], weight, sourceModel="Test"))
                self.allocation[symbol] = weight
                
            
        self.rebalancingTime = algorithm.UtcTime + self.rebalancingPeriod
        self.var.VAA_calculated = True
        
        #return insights
        return Insight.Group( insights )

    def OnSecuritiesChanged(self, algorithm, changes):
        algorithm.Debug("Securities Changed. Added " + str(changes.AddedSecurities))
        symbols = [ x.Symbol for x in changes.AddedSecurities if str(x.Symbol) in self.stocks ]
        history = algorithm.History(symbols, (np.max(self.periods)), Resolution.Daily)
        if history.empty:
            algorithm.Debug("History Error")
            return
    
        for removed in changes.RemovedSecurities:
            if removed.Symbol in self.stocks:
                symbolData_temp = self.symbolDataBySymbol.pop(removed.Symbol, None)
                if symbolData_temp is not None:
                    symbolData_temp.RemoveConsolidators(algorithm)
                    
        for stock in history.index.levels[0]:
            symbol = SymbolCache.GetSymbol(stock)
            algorithm.Debug("Getting Data for " + str(symbol))
            if str(symbol) not in self.symbolDataBySymbol.keys():
                algorithm.Debug("registering symboldata for " + str(symbol))
                symbolData_temp = []
                
                for period in self.periods:
                    #algorithm.Debug("C")
                    tempData = SymbolData(symbol, period)
                    
                    tempData.RegisterIndicators(algorithm, Resolution.Daily)
                    tempData.WarmUpIndicators(history.loc[stock])
                    
                    symbolData_temp.append(tempData)
                
                self.symbolDataBySymbol[str(symbol)] = symbolData_temp
                #algorithm.Debug(symbolData_temp)
                    

class SymbolData:
    def __init__(self, symbol, lookback):
        self.Symbol = symbol
        self.MOM = Momentum('{}.MOM({})'.format(symbol, lookback), lookback)
        self.Consolidator = None
        self.previous = 0
    
    def RegisterIndicators(self, algorithm, resolution):
        #algorithm.Debug("Register Indicators. Alpha")
        self.Consolidator = algorithm.ResolveConsolidator(self.Symbol, resolution)
        algorithm.RegisterIndicator(self.Symbol, self.MOM, self.Consolidator)
    
    def RemoveConsolidators(self, algorithm):
        if self.Consolidator is not None:
            algorithm.SubscriptionManager.RemoveConsolidator(self.Symbol, self.Consolidator)
    
    def WarmUpIndicators(self, history):
        for tuple in history.itertuples():
            self.MOM.Update(tuple.Index, tuple.close)
    
    @property
    def Return(self):
        return float(self.MOM.Current.Value)
    
    @property
    def CanEmit(self):
        if self.previous == self.MOM.Samples:
            return False
        
        self.previous = self.MOM.Samples
        return self.MOM.IsReady
'''
    def __str__(self, **kwargs):
        return '{}: {:.2%}'.format(self.MOM.Name, (1 + self.Return)**252 - 1)
'''
from clr import AddReference
AddReference("QuantConnect.Algorithm.Framework")
AddReference("QuantConnect.Indicators")
AddReference("QuantConnect.Common")

import numpy as np
import pandas as pd
import math

from QuantConnect import *
from QuantConnect.Indicators import *
from QuantConnect.Algorithm.Framework.Alphas import *

from datetime import datetime, timedelta
from pytz import utc
UTCMIN = datetime.min.replace(tzinfo=utc)

class Alpha_ZScore:
    def __init__(self, variables, *args, **kwargs):
        self.Name = "Alpha_ZScore"
        
        self.var = variables
        
        #zscore assets
        self.stocks = [
                    "SPY",
                    "TLT",
                    ]
        """
        zscore parameters
        """
        self.fixed_wt_pct = 0.0 #.50
        self.fixed_wt = {
                            }
        self.vol_factor = 0.50 #TLT = .5, SPY = 1
        self.ext_factor = 4.0 #move too extreme, leave asset
        self.lookback = 252
        self.allocation = {}
        
        #Variable Definitions
        self.resolution = Resolution.Daily
        self.rebalancingTime = UTCMIN
        
        self.days_predicted = 1
        self.rebalancingPeriod = Extensions.ToTimeSpan(self.resolution)*self.days_predicted
        
        for symbol in self.stocks:
            self.allocation[symbol] = 0.0
            
    def Update(self, algorithm, data):
        
        insights = []
        
        if (algorithm.UtcTime <= self.rebalancingTime):
            return insights
        
        safestock = "TLT"   
            
        history = algorithm.History([safestock], self.lookback, Resolution.Daily)
        mean = history['close'].mean()
        sigma = history['close'].std()
        price = float(algorithm.Securities[safestock].Price)
        
        if sigma != 0.0:
            z = (price - mean) / sigma**self.vol_factor
        else:
            z = 0.0
        
        if -self.ext_factor <= z <= self.ext_factor:
            tlt_target = 1.0/(1+math.exp(-1.2*z))*.75 # Pure momentum adding 1 to the sin wave to prevent shorting
        else:
            tlt_target = 0.0
            
        spy_target = (1.0-tlt_target)
        
        allocation_temp = {}
        magnitude = {}
        direction = {}
        
        for sid in self.stocks:
            allocation_temp[sid] = 0.0
            if sid in self.fixed_wt:
                allocation_temp[sid] = self.fixed_wt[sid] * self.fixed_wt_pct
        
        allocation_temp[safestock] += tlt_target * (1.0 - self.fixed_wt_pct)
        allocation_temp["SPY"] += spy_target * (1.0 - self.fixed_wt_pct)
        
        
        predictionInterval = Time.Multiply(Extensions.ToTimeSpan(self.resolution), self.days_predicted)
        
        expected = algorithm.History(self.stocks, 5, Resolution.Daily)["close"].unstack(level=0).dropna().pct_change().dropna().mean() + 1.0
        
        for stock in self.stocks:
            if not expected[stock]: continue
            magnitude[stock] = ((expected[stock]**self.days_predicted)-1.0)/2.0
            
            if magnitude[stock] > -0.005:
                direction[stock] = InsightDirection.Up
            else:
                direction[stock] = InsightDirection.Flat
        
        for symbol in self.allocation:
            if (self.allocation[symbol] != allocation_temp[symbol]) or (self.allocation[symbol] != 0.0) or (allocation_temp[symbol] != 0.0):
                self.allocation[symbol] = allocation_temp[symbol]
                insights.append(Insight(symbol, predictionInterval, InsightType.Price, direction[symbol], magnitude[symbol], self.allocation[symbol], sourceModel="Test"))
                #algorithm.Debug(str(symbol) + " = " + str(self.allocation[symbol]))
        
        #insights = [] #Remove me
        
        #return insights
        self.rebalancingTime = algorithm.UtcTime + self.rebalancingPeriod
        
        return Insight.Group( insights )
        
    def OnSecuritiesChanged(self, algorithm, changes):
        pass
from clr import AddReference
AddReference("QuantConnect.Algorithm.Framework")
AddReference("QuantConnect.Indicators")
AddReference("QuantConnect.Common")

from QuantConnect import *
from QuantConnect.Indicators import *
from QuantConnect.Algorithm.Framework.Alphas import *

from Utility_Functions import *
from datetime import timedelta

import numpy as np
import pandas as pd
import itertools

from datetime import datetime, timedelta
from pytz import utc
UTCMIN = datetime.min.replace(tzinfo=utc)

class Alpha_ACR:
    def __init__(self, variables, *args, **kwargs):
        self.Name = "Alpha_ACR"
        
        self.ACR_assets = [
                        "VOE",
                        "VDC",
                        "XLP",
                        "IJR",
                        ]
        self.ACR_bonds = [
                        "TLT",
                        "TIP",
                        "DBC",
                        "SHY",
                        ]
        self.ACR_sectors = [
                            "XLB", #Materials
                            "XLY", #Consumer Cyclical
                            "XLF", #Financials
                            "IYR", #ISHARES Real Estate
                            "XLP", #Consumer Defensive
                            "XLV", #Healthcare
                            "XLU", #Utilities
                            "XLE", #Energy
                            "XLI", #Industrials
                            "XLK", #Tech
                            ]
        
        self.ACR_fixed = [
                        "SPY",
                        ]
        #self.Hedge = ["VXX",]
            
        self.stocks = self.ACR_assets+self.ACR_bonds+self.ACR_fixed# + self.Hedge
        
        """
        ACR (Asset Class Rotation) parameters
        """
        self.ACR_sector_step = 13 #12% step change = all bonds if 9 of 11 sectors down
        self.ACR_asset_step = 20 #20% step change
        self.allocation = {}
        self.ACR_fixed_weight = [
                                0.0, #SPY
                                ]
        
        self.stocks = self.ACR_assets+self.ACR_bonds+self.ACR_fixed# + self.Hedge
        
        #Variable Definitions
        self.resolution = Resolution.Daily
        self.rebalancingTime = UTCMIN
        
        self.days_predicted = 5
        self.rebalancingPeriod = Extensions.ToTimeSpan(self.resolution)*self.days_predicted
        
        self.var = variables
        
        #for stock in self.ACR_sectors:
        #self.var.AddEquity(stock)
        self.symbolData = {}
        
        for symbol in self.stocks:
                self.allocation[symbol] = 0.0
        
    def Update(self, algorithm, data):
        #algorithm.Debug("Updating Alpha Model.")
        insights = []
        
        if (algorithm.UtcTime <= self.rebalancingTime):
            return insights
        
        for sid in self.stocks:
            if not sid in self.allocation:
                self.allocation[sid] = 0.0
        
        ACR_assets_weight = np.zeros(len(self.ACR_assets))
        ACR_bonds_data = pd.DataFrame(0, columns=['Weight','Ratio','20Day','60Day'],index=self.ACR_bonds) 
        ACR_sectors_data = pd.DataFrame(0, columns=['Ratio','20Day','200Day'],index=self.ACR_sectors)
        """
        Determine sector trends and calculate weight to assets/bonds
        """
        ACR_sectors_data.loc[:,'20Day'] = algorithm.History(self.ACR_sectors, 20, Resolution.Daily)["close"].unstack(level=0).mean()
        ACR_sectors_data.loc[:, '200Day'] = algorithm.History(self.ACR_sectors, 200, Resolution.Daily)["close"].unstack(level=0).mean()
        ACR_sectors_data['Ratio'] = ACR_sectors_data['20Day']/ACR_sectors_data['200Day'] - 1
        
        ACR_bonds_weight = len(ACR_sectors_data[ACR_sectors_data['Ratio'] < 0]) * self.ACR_sector_step/100.0
        if ACR_bonds_weight > 1.0:
            ACR_bonds_weight = 1.0
        ACR_bonds_weight = ACR_bonds_weight * (1-sum(self.ACR_fixed_weight))
        
        """
        Determine bond trends and which duration to be in
        """
        if ACR_bonds_weight > 0.0:
            ACR_bonds_data.loc[:,'20Day'] = algorithm.History(self.ACR_bonds, 20, Resolution.Daily)["close"].unstack(level=0).mean()
            ACR_bonds_data.loc[:, '60Day'] = algorithm.History(self.ACR_bonds, 60, Resolution.Daily)["close"].unstack(level=0).mean()
            ACR_bonds_data['Ratio'] = ACR_bonds_data['20Day']/ACR_bonds_data['60Day'] - 1
            ACR_bonds_data['Weight'] = 0
            ACR_bonds_data.loc[ACR_bonds_data['Ratio'].idxmax(), 'Weight'] = ACR_bonds_weight
        #log.info(self.ACR_bonds_data)
        
        returns = algorithm.History(self.ACR_assets, 126, Resolution.Daily)["close"].unstack(level=0).dropna().pct_change().dropna() + 1.0
        
        expected = algorithm.History(self.stocks, 20, Resolution.Daily)["close"].unstack(level=0).dropna().pct_change().dropna().mean() + 1.0
        
        """
        Create portfolio combinations
        """
        n = len(self.ACR_assets)
        steps = [x/100.0 for x in range(0,101,int(self.ACR_asset_step))]
        a = [steps for x in range(n)]
        b = list(itertools.product(*a))
        x = [sum(i) for i in b]
        port = pd.DataFrame(b)
        port['Sum'] = x
        port = port[port.Sum == 1]
        del port['Sum']
        """
        Score and Weight portoflio
        """
        port_returns = pd.DataFrame(np.dot(returns, port.T), index=returns.index)
        port_metrics = self.ACR_get_specs(port_returns)
        
        port_metrics = self.ACR_score(port_metrics)
        
        port_metrics['Z3'] = port_metrics.ZMean\
        -port_metrics.ZSTD\
        -port_metrics.ZDownSide\
        +port_metrics.ZAnnualized\
        -port_metrics.ZMax_Draw\
        -port_metrics.ZSTD10\
        +port_metrics.ZMean10\
        +port_metrics.ZMinimum15 
        
        
        port_metrics = port_metrics.sort_values(by='Z3', ascending=False)
        
        portfolios = port
        portfolios.columns = list(returns.columns.values)
        best = pd.concat([pd.DataFrame(portfolios.iloc[port_metrics['Z3'].idxmax()]).T])
        #log.info(best.loc[:, (best != 0).any(axis=0)].T)
        best = pd.DataFrame(portfolios.iloc[port_metrics['Z3'].idxmax()])
        #log.info(best)
        ACR_assets_weight = [i[0]*(1-ACR_bonds_weight-sum(self.ACR_fixed_weight)) for i in best.values]
        
        predictionInterval = Time.Multiply(Extensions.ToTimeSpan(self.resolution), self.days_predicted)
        
        allocation_temp = {}
        magnitude = {}
        direction = {}
        risk_weight = 0
        for x in range(n):
            allocation_temp[self.ACR_assets[x]] = ACR_assets_weight[x]#*.95
            #expected_temp[self.ACR_assets[x]] = 
            risk_weight += ACR_assets_weight[x]
        
        for stock in self.stocks:
            magnitude[stock] = ((expected[stock]**self.days_predicted)-1.0)/5.0
            #magnitude[stock] = 0.001
            
            #algorithm.Debug(str(stock) + " magnitude = " + str(magnitude[stock]))
            
            if magnitude[stock] > -0.01:
                direction[stock] = InsightDirection.Up
            else:
                direction[stock] = InsightDirection.Flat
                
            magnitude[stock] = 0.001
        
        #self.allocation[self.Hedge[0]] = risk_weight * .05
        
        for stock in self.ACR_bonds:
            allocation_temp[stock] = ACR_bonds_data.loc[stock, 'Weight']
        for x in range(len(self.ACR_fixed)):
            allocation_temp[self.ACR_fixed[x]] = self.ACR_fixed_weight[x]
        
        for symbol in self.allocation:
            if (self.allocation[symbol] != allocation_temp[symbol]) or (self.allocation[symbol] != 0.0) or (allocation_temp[symbol] != 0.0):
                #if allocation_temp[symbol] > self.allocation[symbol]:
                self.allocation[symbol] = allocation_temp[symbol]
                insights.append(Insight(symbol, predictionInterval, InsightType.Price, InsightDirection.Up, magnitude[symbol], self.allocation[symbol], sourceModel="Test"))
                #algorithm.Debug(str(symbol) + " = " + str(self.allocation[symbol]))
        
        #insights = [] #Remove me
        
        #return insights
        self.rebalancingTime = algorithm.UtcTime + self.rebalancingPeriod
        
        return Insight.Group( insights )
        
    def ACR_drawdown(self, returns):
        mat = returns.cumprod().values
        [n, m] = np.shape(mat)
        maxes = np.maximum.accumulate(np.array(mat))
        for i in range(0,n):
            for j in range(m):
                mat[i,j] = mat[i,j] / maxes[i,j]
        df = pd.DataFrame(mat)
        df[df > 1] = 1
        return df
        
    def ACR_moving_returns(self, returns, w):
        mat = returns.values
        [n, m] = np.shape(mat)
        ret = np.zeros(shape = (n-w+1,m))
        for i in range(w-1,n):
            for j in range(m):
                ret[i-w+1,j] = np.power(np.prod(mat[(i-w+1):i+1,j]),(1.0/w))- 1.0
        return pd.DataFrame(ret)
        
    def ACR_get_specs(self, returns):
        metrics = pd.DataFrame((returns.mean()),columns=['Mean']) - 1.0
        metrics['STD'] = pd.DataFrame((returns.std()))
        metrics['Annualized'] = np.power(returns.cumprod().values.tolist()[-1],1.0/len(returns))- 1.0
        
        downside = returns.copy(deep=True) - 1
        downside[downside > 0] = 0
        downside = downside ** 2
        metrics['DownSide'] = pd.DataFrame(downside.mean() ** 0.5)
        
        draw = self.ACR_drawdown(returns)
        metrics['Max_Draw'] = 1.0 - draw.min().values
        ret15 = self.ACR_moving_returns(returns,21)
        metrics['Minimum15'] = ret15.min().values
        
        ret10 = self.ACR_moving_returns(returns,21)
        metrics['Mean10'] = ret10.mean().values
        metrics['STD10'] = ret10.std().values
        
        return metrics
        
    def ACR_zscore(self, stocks, var, var_save):
        stocks[var_save] = (stocks[var] - stocks[var].mean())/stocks[var].std(ddof=0)
        return stocks 
        
    def ACR_score(self, metrics):
        metrics = self.ACR_zscore(metrics, 'Mean', 'ZMean')
        metrics = self.ACR_zscore(metrics, 'STD', 'ZSTD')
        metrics = self.ACR_zscore(metrics, 'Annualized', 'ZAnnualized')
        metrics = self.ACR_zscore(metrics, 'DownSide', 'ZDownSide')
        metrics = self.ACR_zscore(metrics, 'Max_Draw', 'ZMax_Draw')
        metrics = self.ACR_zscore(metrics, 'Minimum15', 'ZMinimum15')
        metrics = self.ACR_zscore(metrics, 'STD10', 'ZSTD10')
        metrics = self.ACR_zscore(metrics, 'Mean10', 'ZMean10')
        return metrics
            
    def OnSecuritiesChanged(self, algorithm, changes):
        pass
from clr import AddReference
AddReference("QuantConnect.Common")
AddReference("QuantConnect.Algorithm.Framework")

from QuantConnect import Resolution, Extensions
from QuantConnect.Algorithm.Framework.Alphas import InsightCollection, InsightDirection
from QuantConnect.Algorithm.Framework.Portfolio import PortfolioConstructionModel, PortfolioTarget
from itertools import groupby
from datetime import datetime
from pytz import utc
UTCMIN = datetime.min.replace(tzinfo=utc)

import numpy as np

class Confidence_Weighted_Portfolio(PortfolioConstructionModel):

    def __init__(self, resolution = Resolution.Daily, reserve = 0, leverage = 1.0, num_alphas = 1.0, normalize = False):
        
        self.insightCollection = InsightCollection()
        self.removedSymbols = []
        self.rebalancingTime = UTCMIN
        self.rebalancingPeriod = Extensions.ToTimeSpan(resolution)
        self.allocation = {}
        self.reserved = reserve
        self.max_leverage = leverage
        self.normalize = normalize
        self.num_alphas = num_alphas
        
        self.symbol_list = []

    def CreateTargets(self, algorithm, insights):
        targets = []
        
        if (algorithm.UtcTime <= self.rebalancingTime and
            len(insights) == 0 and
            self.removedSymbols is None):
            return targets
            
        self.insightCollection.AddRange(insights)
        
        # Create Sell target for each security that was removed from the universe
        if self.removedSymbols is not None:
            universeDeselectionTargets = [ PortfolioTarget(symbol, 0) for symbol in self.removedSymbols ]
            targets.extend(universeDeselectionTargets)
            self.removedSymbols = None
            
        if self.addedSymbols is not None:
            for symbol in self.addedSymbols:
                self.allocation[symbol] = {}
            self.addedSymbols = None
            
        # Get insight that haven't expired of each symbol that is still in the universe
        activeInsights = self.insightCollection.GetActiveInsights(algorithm.UtcTime)
        
        # Get the last generated active insight for each symbol
        lastActiveInsights = []
        for symbol, g in groupby(activeInsights, lambda x: x.Symbol):
            lastActiveInsights.append(sorted(g, key = lambda x: x.GeneratedTimeUtc)[-1])
            
        #Gets Adjusted Portfolio value
        port_value_adjusted = (float(algorithm.Portfolio.TotalPortfolioValue) - self.reserved) * self.max_leverage
        
        for insight in lastActiveInsights:
            symbol = insight.Symbol
            allocation = insight.Confidence
            alpha = insight.SourceModel
            
            #Calculate required rebalance amount for each allocation
            goal_value = (port_value_adjusted * allocation)
            
            #Adjusted % allocation
            self.allocation[symbol][alpha] = goal_value/float(algorithm.Portfolio.TotalPortfolioValue)/self.num_alphas
        
        
        combined_weight = {}
        for symbol in self.allocation.keys():
            wt = sum(list(self.allocation[symbol].values()))
            combined_weight[symbol] = wt
        
        #option to normalize target_portfolio to fill all availible leverage
        if self.normalize:
            original_wt = sum(np.abs(list(combined_weight.values())))
            if original_wt > 0.0:
                factor = self.max_leverage/original_wt
            else:
                factor = 0.0
            
            for symbol in combined_weight.keys():        
                combined_weight[symbol] = combined_weight[symbol]*factor
            
        
        for symbol in combined_weight.keys():
            
            target = PortfolioTarget.Percent(algorithm, symbol,  combined_weight[symbol])
            
            if target != None:
                targets.append(target)
                
                #Log final desired allocation
                #algorithm.Debug(str(symbol) + ". Allocation = " + str(round(self.allocation[symbol]*100,1)) + "% > " + str(int(target.Quantity)))
            
            else:
                algorithm.Debug("Target Error on " + str(symbol) + ". Should be " + str(round(combined_weight[symbol]*100,1)) + "%")
                
        self.rebalancingTime = algorithm.UtcTime + self.rebalancingPeriod
        
        return targets
        
    def OnSecuritiesChanged(self, algorithm, changes):
        
        self.addedSymbols = [x.Symbol for x in changes.AddedSecurities]
        
        
        # Get removed symbol and invalidate them in the insight collection
        self.removedSymbols = [x.Symbol for x in changes.RemovedSecurities]
        self.insightCollection.Clear(self.removedSymbols)