Overall Statistics |
Total Trades 63 Average Win 0.69% Average Loss -0.41% Compounding Annual Return 12.989% Drawdown 15.300% Expectancy 0.306 Net Profit 8.650% Sharpe Ratio 0.828 Probabilistic Sharpe Ratio 42.381% Loss Rate 52% Win Rate 48% Profit-Loss Ratio 1.71 Alpha 0.115 Beta 0.008 Annual Standard Deviation 0.14 Annual Variance 0.02 Information Ratio -0.157 Tracking Error 0.383 Treynor Ratio 14.44 Total Fees $90.95 |
from System import * from clr import AddReference AddReference("QuantConnect.Algorithm") 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.Portfolio import * from Selection.FundamentalUniverseSelectionModel import FundamentalUniverseSelectionModel from QuantConnect.Algorithm.Framework.Portfolio import PortfolioConstructionModel class NadionUncoupledPrism(QCAlgorithm): def Initialize(self): self.SetStartDate(2020, 1, 1) self.SetEndDate(2020, 12, 1) self.SetCash(100000) self.AddEquity("SPY", Resolution.Daily) self.AddEquity("BND", Resolution.Daily) self.SetBenchmark("SPY") #self.SetAlpha() self.AddUniverseSelection(TechnologyUniverseModule()) self.AddRiskManagement(NullRiskManagementModel()) self.SetPortfolioConstruction(NullPortfolioConstructionModel()) self.SetExecution(ImmediateExecutionModel()) self.UniverseSettings.Resolution = Resolution.Daily self.ema = self.EMA("SPY", 100, Resolution.Daily) self.ema_BND = self.EMA("BND", 100, Resolution.Daily) self.SetWarmUp(100) def OnSecuritiesChanged(self, changes): self.changes = changes self.BND = self.Securities["SPY"].Close < self.ema.Current.Value and \ self.Securities["BND"].Close > self.ema_BND.Current.Value self.SPY = self.Securities["SPY"].Close > self.ema.Current.Value if not self.Portfolio.Invested: if self.SPY == True: for security in self.changes.RemovedSecurities: if security.Invested: self.Liquidate(security.Symbol) for security in self.changes.AddedSecurities: if not security.Invested: self.SetHoldings(security.Symbol, .05) elif self.BND == True: self.SetHoldings([PortfolioTarget("BND", 1.00)]) elif self.Portfolio.Invested: if self.Portfolio.Invested and not self.Portfolio["BND"].Invested: if self.BND == True: self.Liquidate() self.SetHoldings([PortfolioTarget("BND", 1.00)]) elif self.Portfolio["BND"].Invested: if self.SPY == True: self.Liquidate("BND") for security in self.changes.RemovedSecurities: if security.Invested: self.Liquidate(security.Symbol) for security in self.changes.AddedSecurities: if not security.Invested: self.SetHoldings(security.Symbol, .05) if self.BND == True: self.Liquidate() self.SetHoldings([PortfolioTarget("BND", 1.00)]) else: return class TechnologyUniverseModule(FundamentalUniverseSelectionModel): #This module selects the most liquid stocks listed on the Nasdaq Stock Exchange. def __init__(self, filterFineData = True, universeSettings = None, securityInitializer = None): #Initializes a new default instance of the TechnologyUniverseModule super().__init__(filterFineData, universeSettings, securityInitializer) self.numberOfSymbolsCoarse = 1000 self.numberOfSymbolsFine = 100 self.dollarVolumeBySymbol = {} self.lastMonth = -1 def SelectCoarse(self, algorithm, coarse): ''' Performs a coarse selection: -The stock must have fundamental data -The stock must have positive previous-month close price -The stock must have positive volume on the previous trading month ''' if algorithm.Time.month == self.lastMonth: return Universe.Unchanged sortedByDollarVolume = sorted([x for x in coarse if x.HasFundamentalData and x.Volume > 0 and x.Price > 0], key = lambda x: x.DollarVolume, reverse=True)[:self.numberOfSymbolsCoarse] self.dollarVolumeBySymbol = {x.Symbol:x.DollarVolume for x in sortedByDollarVolume} # If no security has met the QC500 criteria, the universe is unchanged. if len(self.dollarVolumeBySymbol) == 0: return Universe.Unchanged return list(self.dollarVolumeBySymbol.keys()) def SelectFine(self, algorithm, fine): sortedByDollarVolume = sorted([x for x in fine if x.CompanyReference.CountryId == "USA" and x.CompanyReference.PrimaryExchangeID == "NAS" and x.CompanyReference.IndustryTemplateCode == "N"], key = lambda x: self.dollarVolumeBySymbol[x.Symbol], reverse=True) if len(sortedByDollarVolume) == 0: return Universe.Unchanged self.lastMonth = algorithm.Time.month return [x.Symbol for x in sortedByDollarVolume[:20]] class NullPortfolioConstructionModel(PortfolioConstructionModel): def CreateTargets(self, algorithm, insights): return [] class ImmediateExecutionModel(ExecutionModel): def __init__(self): self.targetsCollection = PortfolioTargetCollection() def Execute(self, algorithm, targets): # for performance we check count value, OrderByMarginImpact and ClearFulfilled are expensive to call self.targetsCollection.AddRange(targets) if self.targetsCollection.Count > 0: for target in self.targetsCollection.OrderByMarginImpact(algorithm): # calculate remaining quantity to be ordered quantity = OrderSizing.GetUnorderedQuantity(algorithm, target) if quantity != 0: algorithm.MarketOrder(target.Symbol, quantity) self.targetsCollection.ClearFulfilled(algorithm)