Overall Statistics
Total Trades
34
Average Win
0%
Average Loss
-1.58%
Compounding Annual Return
69.580%
Drawdown
10.400%
Expectancy
-1
Net Profit
22.448%
Sharpe Ratio
2.243
Loss Rate
100%
Win Rate
0%
Profit-Loss Ratio
0
Alpha
1.502
Beta
-49.033
Annual Standard Deviation
0.243
Annual Variance
0.059
Information Ratio
2.162
Tracking Error
0.243
Treynor Ratio
-0.011
Total Fees
$185.90
import numpy as np
import pandas as pd

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

from datetime import datetime, timedelta
from System import *
from QuantConnect import *
from QuantConnect.Algorithm import *
from QuantConnect.Data.Market import TradeBar
import json
import math
from QuantConnect.Data import SubscriptionDataSource
from QuantConnect.Python import PythonData

class TemplateAlgorithmUniverseSelection(QCAlgorithm):
    '''Advanced Template Architecture'''

    def Initialize(self):
  
        '''Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialize.'''

        # Chart - Master Containers for the Charts:
        stockPlot_1 = Chart('RSI')
        stockPlot_2 = Chart('Margin Remaining')
        
        #Establish universe-wide settings
        self.UniverseSettings.Resolution = Resolution.Daily
        self.UniverseSettings.Leverage = 2

        #Initial investment and backtest period
        self.SetStartDate(2019,1,1)                                  #Set Start Date
        self.SetEndDate(datetime.now().date() - timedelta(1))        #Set End Date
        self.SetCash(1000000)                                        #Set Strategy Cash

        #Initialize list of Open Orders
        self.OpenOrders = self.Transactions.GetOpenOrders()
        
        #Capture initial investment for risk off purposes
        self.marginRemaining = self.Portfolio.MarginRemaining
        self.OpenPortValue = self.Portfolio.TotalPortfolioValue
        self.ClosingPortValue = self.Portfolio.TotalPortfolioValue
        self.CurrentPortValue = self.Portfolio.TotalPortfolioValue
        self.CurrentHoldValue = self.Portfolio.TotalHoldingsValue
        self.OpenHoldValue = self.Portfolio.TotalHoldingsValue 
        self.ClosingHoldValue = self.Portfolio.TotalHoldingsValue   
        
        #Universe
        self.AddEquity("SPY", Resolution.Daily)        
        self.AddUniverse(self.CoarseSelectionFunction, self.MyFineFundamentalFunction)

        #Brokerage Model
        self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage)       
        
        '''Schedule Functions Here'''
        
        self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.AfterMarketOpen("SPY", 1), self.CheckLiveTrading)
        self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.AfterMarketOpen("SPY", 1), self.Charts)        
        self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.AfterMarketOpen("SPY", 1), self.CheckDailyLosses)
        self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.AfterMarketOpen("SPY", 1), self.UpdatePortValues)
        
        for x in range (20,390,20):
            self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.AfterMarketOpen("SPY", x), self.UpdatePortValues)
            
        for y in range (23,390,23):    
            self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.AfterMarketOpen("SPY", y), self.CheckDailyLosses) 
    
        self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.BeforeMarketClose("SPY", 1), self.CapturePortfolioValue)
        self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.BeforeMarketClose("SPY", 1), self.ClearOpenOrders)  
        
        '''Set Warmup Here'''
        self.SetWarmup(TimeSpan.FromDays(30))
        
        
#Universe Selection
    def CoarseSelectionFunction(self, coarse):
        
        sortedByDollarVolume = sorted(coarse, key=lambda x: x.DollarVolume, reverse=True)
        filtered = [ x.Symbol for x in sortedByDollarVolume 
                        if x.Price > 10 and x.DollarVolume > 10000000 ]
            
        return filtered[:500]

    def MyFineFundamentalFunction(self, fine):
        
        sortedByPeRatio = sorted(fine, key=lambda x: x.ValuationRatios.PERatio, reverse=False)
        
        return [ x.Symbol for x in sortedByPeRatio[:10] ]    

#OnData 
    def OnData(self, data):
        '''OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.'''
        '''Arguments:
            data: Slice object keyed by symbol containing the stock data'''
            
        weighting = 1.0 / self.Securities.Count
        
        for security in self.Securities.Values:
            if not self.Securities[security.Symbol].Invested:
                self.SetHoldings(security.Symbol, weighting)
        
#Charts
    def Charts(self):
        
        #Plot any relevant portfolio metrics
        self.Plot('Margin Remaining', 'Margin Remaining', self.marginRemaining)
        #self.PlotIndicator('RSI', self.tslaRsi, self.vixRsi, self.spyRsi)

#AtClose
    def OnEndOfDay(self):
        
        self.Log("Trading Day Has Ended")
      
#MarginCallWarning                
    def OnMarginCallWarning(self):
        
        #Get a list of open orders to avoid margin issues
        self.OpenOrders = self.Transactions.GetOpenOrders()
        
        #Cancel any open orders.
        if len(self.OpenOrders)> 0:
            for x in self.OpenOrders:
                 self.Transactions.CancelOrder(x.Id) 

        #Rebalance to free up capital
        self.Log("Rebalacing due to tight margin conditions")                 
        self.MarginCall()
        self.Log("WARNING: Day Start Portfolio Value: ${0} | Current Portfolio Value: ${1} | Loss: {2}%".format(
            
            round(self.ClosingPortValue,2), 
            round(self.Portfolio.TotalPortfolioValue,2), 
            round( ( (int(self.ClosingPortValue)/int(self.Portfolio.TotalPortfolioValue)) -1)*100,2), ) )        

#CheckLive        
    #Check connection at open and note the value gap
    def CheckLiveTrading(self):
        
        #Capture portfolio metrics at open. Verify live connection. Log previous close and overnight gap up/down
        self.OpenOrders = self.Transactions.GetOpenOrders()
        self.OpenPortValue = self.Portfolio.TotalPortfolioValue
        self.OpenHoldValue = self.Portfolio.TotalHoldingsValue
        self.Gap = round( ( ( ( int(self.OpenPortValue)/int(self.ClosingPortValue) ) - 1) * 100),2)
 
        #Perform actions based on overnight changes in portfolio value
        if self.Gap >= 10.00:
            self.Log("Huge gap up today! {0}%!".format(self.Gap))
            self.OhWow()        
            
        if self.Gap <= -4.25:
            self.Log("Huge gap down today! {0}%!".format(self.Gap))
            self.OhShit()             
            
        self.Log("Trading Live! || Yesterday's Closing Value: ${0}|| Opening Value: {1}% gap".format(self.ClosingPortValue, self.Gap))
        
        return
        
#CaputureValue
    #Capture the closing value of the portfolio and any open orders
    def CapturePortfolioValue(self):
        
        self.OpenOrders = self.Transactions.GetOpenOrders()
        self.ClosingPortValue = self.Portfolio.TotalPortfolioValue
        self.ClosingHoldValue = self.Portfolio.TotalHoldingsValue
        
        self.Log("End Of Day Portfolio Values Have Been Captured")
        
        return
        
#ClearOrders        
    #Clear open orders if there are 5 or more    
    def ClearOpenOrders(self):
        
            #Get a list of open orders to avoid margin issues
            self.OpenOrders = self.Transactions.GetOpenOrders()
            
            #Cancel any open orders.
            if len(self.OpenOrders)> 5:
                for x in self.OpenOrders:
                     self.Transactions.CancelOrder(x.Id)
                
                self.Log("Open Orders Have Been Closed.")   
                
            else:
                return
            
#Update Portfolio Values    
    def UpdatePortValues(self):
        
        if(self.IsMarketOpen("SPY")):
                
            self.marginRemaining = self.Portfolio.MarginRemaining
            self.CurrentPortValue = self.Portfolio.TotalPortfolioValue
            self.CurrentHoldValue = self.Portfolio.TotalHoldingsValue
    
            self.Log("Portfolio Values Have Been Updated")            
            
#CheckLosses            
    #Check intraday losses and run a defensive function if a 5.6% drop is recognized at any time      
    def CheckDailyLosses(self):
        
        if(self.IsMarketOpen("SPY")): 
            
            self.CurrentPerformance = round( ((float(self.CurrentPortValue)/float(self.ClosingPortValue))-1)*100,2)
            
            if (self.CurrentPortValue <= self.ClosingPortValue*0.944):
                    self.HighLosses()
                
            else: self.Log("Current Performance: {0}%".format(self.CurrentPerformance))
            
            return
        
#HighLosses        
    #Liquidate most holdings after a 5.6% drop from previous portfolio close value.
    def HighLosses(self):
            
        #Get a list of open orders to avoid margin issues
        self.OpenOrders = self.Transactions.GetOpenOrders()
        
        #Cancel any open orders.
        if len(self.OpenOrders)> 0:
            for x in self.OpenOrders:
                 self.Transactions.CancelOrder(x.Id)
        
        #Set portfolio to risk averse proportions and log important information
        self.OhShit()
        
        #Log important portfolio information when this function fires    
        self.Log("WARNING: Rebalancing due to excessive daily losses || Day Start Portfolio Value: ${0} || Current Portfolio Value: ${1} || Loss: {2}% || Gap at open: {3}%".format(
            
            round(self.ClosingPortValue,2), 
            round(self.Portfolio.TotalPortfolioValue,2), 
            round( ( (int(self.ClosingPortValue)/int(self.Portfolio.TotalPortfolioValue)) -1)*100,2),
            self.Gap) )
        
        #Reset the reference point to catch any further 5.6% decreases with the new holdings.   
        self.ClosingPortValue = self.Portfolio.TotalPortfolioValue 
        
        #If there were any open orders left this will log how many.  We cancelled them all, so this would be on the broker or connectivity
        if (len(self.OpenOrders)> 0):
            self.Log("Number of open orders: {0}".format( len(self.OpenOrders ))) 

        return
    
#Ohshit        
    def OhShit(self):
        return
            
#OhWow
    def OhWow(self):
        return
    
#MarginCall
    def MarginCall(self):
        return
            
#SPY       
    def SpyFunc(self):
        
        self.Log("SPY Function Has Fired.  || SPY RSI: {0}".format(
            round(self.spyRsi.Current.Value),3))
        
        #Used to control leverage
        self.OpenOrders = self.Transactions.GetOpenOrders()

    
        return
    
#TSLA       
    def TslaFunc(self):
        
        self.Log("TSLA Function Has Fired.  || Relevant Metrics: TSLA RSI: {0}".format(
            round(self.tslaRsi.Current.Value,3)))
        
        #Refresh open orders
        self.OpenOrders = self.Transactions.GetOpenOrders()
        
    
        return  
    
#TVIX
    def Func3(self):
        
        #Get open orders. Used to prevent inappropriate use of leverage
        self.OpenOrders = self.Transactions.GetOpenOrders()

        return

'''        
class Vix(PythonData):
    #New VIX Object

    def GetSource(self, config, date, isLiveMode):
        #if isLiveMode:
        return SubscriptionDataSource("http://www.cboe.com/publish/scheduledtask/mktdata/datahouse/vixcurrent.csv", SubscriptionTransportMedium.RemoteFile);

    def Reader(self, config, line, date, isLiveMode):
        
        # New VIX object
        index = Vix()
        index.Symbol = config.Symbol   
        
        #if isLiveMode:
        if not (line.strip() and line[0].isdigit()): return None


        try:
            # Example File Format:
            # Date,       Open       High        Low       Close     Volume      Turnover
            # 1/1/2008  7792.9    7799.9     7722.65    7748.7    116534670    6107.78
            data = line.split(',')
            index.Time = datetime.strptime(data[0], "%m/%d/%Y")
            index.Value = data[4]
            index["Close"] = float(data[4])


        except ValueError:
                # Do nothing
                return None

        return index
'''