Overall Statistics
Total Trades
6231
Average Win
0.11%
Average Loss
-0.03%
Compounding Annual Return
10.874%
Drawdown
16.800%
Expectancy
1.114
Net Profit
180.898%
Sharpe Ratio
0.835
Probabilistic Sharpe Ratio
24.135%
Loss Rate
55%
Win Rate
45%
Profit-Loss Ratio
3.69
Alpha
0.1
Beta
-0.035
Annual Standard Deviation
0.115
Annual Variance
0.013
Information Ratio
-0.13
Tracking Error
0.18
Treynor Ratio
-2.723
Total Fees
$6875.14
from datetime import timedelta
import numpy as np
from scipy import stats
from collections import deque

class FrameworkAlgorithm(QCAlgorithm):
    
    def Initialize(self):
        self.SetStartDate(2010, 1, 1)   
        self.SetEndDate(2019, 12, 31)    
        self.SetCash(100000)   
        
        self.tickers = ["QQQ","PQSC","IYC","IYK","IGV","IHI","ITA","ITB","SMH","GLD","SBUG","TLH","TLT","EDV","CWB"]
        self.UniverseSettings.Resolution = Resolution.Daily
        self.sym=[]
        for x in self.tickers:
            self.sym.append(Symbol.Create(x, SecurityType.Equity, Market.USA))
        self.SetUniverseSelection( ManualUniverseSelectionModel(self.sym) )

        # Alpha Model
        self.SetAlpha(MOMAlphaModel())
        
        # PortfolioConstruction Model
        self.SetPortfolioConstruction(EqualWeightingPortfolioConstructionModel())
        
        # RiskManagement Model 
        self.SetRiskManagement(MaximumDrawdownPercentPerSecurity(1))
        
        # Execution Model 
        self.SetExecution(ImmediateExecutionModel())

        
class MOMAlphaModel(AlphaModel): 
    def __init__(self):
        self.mom = []
        self.slopy={}
        
    
    def OnSecuritiesChanged(self, algorithm, changes):
        

        for security in changes.AddedSecurities:
            symbol = security.Symbol

            self.slopy[symbol] = custom_slope(symbol, 100)
            history = algorithm.History(symbol, 100, Resolution.Daily)
            self.slopy[symbol].Warmup(history)
            algorithm.RegisterIndicator(symbol, self.slopy[symbol], Resolution.Daily)
            self.mom.append({"symbol":symbol, "indicator": self.slopy[symbol]})
            
            
            
    def Update(self, algorithm, data):
        insights = []
        
        ordered = sorted(self.mom, key=lambda kv: kv["indicator"].Current.Value, reverse=True)[:4]
        
        for x in ordered:
            symbol = x['symbol']
            
            #if  self.slopy[symbol].IsReady : 
            
            insights.append( Insight.Price(symbol, timedelta(1), InsightDirection.Up) )    
        return insights
        
        
class custom_slope(PythonIndicator):
    def __init__(self,symbol, periods):
        self.symbol=symbol
        self.queue = deque(maxlen=periods)
        self.Value = 0
        self.Time=None
        #self.IsReady=False

    def Update(self,input):
        self.queue.appendleft(input.Close)
        count = len(self.queue)
      
        if count == self.queue.maxlen:    
            y = np.log(self.queue)
            x = [range(len(y))]
            slope, intercept, r_value, p_value, std_err = stats.linregress(x, y)
            self.Value=slope * 10000
            #self.IsReady=True
  
        
    def Warmup(self,history): 
        if self.symbol not in history:
            return
        for index, row in history.loc[self.symbol].iterrows():
            self.queue.Add(row["close"])
            self.Time=index