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 '''