Overall Statistics |
Total Trades 3385 Average Win 0.38% Average Loss -0.27% Compounding Annual Return 22.178% Drawdown 35.100% Expectancy 0.167 Net Profit 118.953% Sharpe Ratio 1.188 Probabilistic Sharpe Ratio 57.216% Loss Rate 52% Win Rate 48% Profit-Loss Ratio 1.41 Alpha 0.209 Beta -0.1 Annual Standard Deviation 0.164 Annual Variance 0.027 Information Ratio 0.221 Tracking Error 0.257 Treynor Ratio -1.948 Total Fees $0.00 |
from Execution.ImmediateExecutionModel import ImmediateExecutionModel class VentralModulatedCompensator(QCAlgorithm): def Initialize(self): self.SetStartDate(2016, 11, 2) # Set Start Date self.SetCash(3500) # Set Strategy Cash # self.AddEquity("SPY", Resolution.Minute) self.SetExecution(ImmediateExecutionModel()) self.UniverseSettings.Leverage = 1 self.UniverseSettings.Resolution = Resolution.Daily self.SetUniverseSelection(FineFundamentalUniverseSelectionModel(self.CoarseSelectionFunction, self.FineSelectionFunction, None, None)) self.SetSecurityInitializer(self.CustomSecurityInitializer) #self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage) #self.Securities[AddedSecurities].FeeModel = ConstantFeeModel(0) #self.ActiveSecurities.FeeModel = ConstantFeeModel(0) self.UniverseSettings.MinimumTimeInUniverse = 10 self.averages = { } def CustomSecurityInitializer(self, security): security.SetFeeModel(CustomFeeModel()) def CoarseSelectionFunction(self, coarse): selected = [] universe = sorted(coarse, key=lambda c: c.DollarVolume, reverse=True) universe = [c for c in universe if c.Price > 10] for coarse in universe: symbol = coarse.Symbol if symbol not in self.averages: # 1. Call history to get an array of 200 days of history data history = self.History(symbol, 31, Resolution.Daily) #2. Adjust SelectionData to pass in the history result self.averages[symbol] = SelectionData(history) self.averages[symbol].update(self.Time, coarse.AdjustedPrice) if self.averages[symbol].is_ready() and self.averages[symbol].fast > self.averages[symbol].slow: selected.append(symbol) return selected def FineSelectionFunction(self, fine): #sorted_by_ev = sorted(fine, key=lambda x: x.ValuationRatios.NormalizedPEGatio, reverse=False) #sorted_by_ev = sorted(fine, key=lambda x: x.ValuationRatios.EVToEBITDA.latest > 0, reverse=False) #sorted_by_ev = sorted(fine, key=lambda x: x.ValuationRatios.PricetoEBITDA > 0, reverse=False) #sorted_by_ev = sorted(fine, key=lambda x: x.ValuationRatios.PCFRatio,reverse=False) #sorted_by_ev = sorted(fine, key=lambda x: x.ValuationRatios.CashReturn, reverse=True) #sorted_by_roic = sorted(fine, key=lambda x: x.OperationRatios.ROIC.ThreeMonths, reverse=True)[:150] sorted_by_ev = sorted(fine, key=lambda x: x.ValuationRatios.PricetoEBITDA, reverse=True)[:100] sorted_by_roic = sorted(sorted_by_ev, key=lambda x: x.OperationRatios.ROIC.ThreeMonths, reverse=True)[:50] sorted_by_bookvalue = sorted(sorted_by_roic, key=lambda x: x.ValuationRatios.BookValuePerShare, reverse = False)[:15] #CashReturn = 8.98%, 4.2 alpha #EVToRevenue3YrAvg = Not worth pursuing? #EVToFCF3YrAvg #PBRatio3YrAvg = 9.15%, 4.8 alpha #EarningYield #NormalizedPEGatio #PB/Cash Return = 1.235, alpha = .177 #ROIC/PBRATIO3YRAVG = 88.78%, alpha = .194 return [x.Symbol for x in sorted_by_bookvalue] #sorted_by_cash = sorted(sorted_by_roic, key=lambda x: x.ValuationRatios.CashReturn, reverse=True) #return [x.Symbol for x in sorted_by_cash[:60]] #sorted_by_pb = sorted(sorted_by_roic, key=lambda x: x.ValuationRatios.PBRatio3YrAvg, reverse=False) #return [x.Symbol for x in sorted_by_pb[:15]] def OnSecuritiesChanged(self, changes): self.changes = changes self.Log(f"OnSecuritiesChanged({self.Time}):: {changes}") for security in self.changes.RemovedSecurities: if security.Invested: self.Liquidate(security.Symbol) for security in self.changes.AddedSecurities: self.SetHoldings(security.Symbol, 0.04) class CustomFeeModel: def GetOrderFee(self, parameters): return OrderFee(CashAmount(0, 'USD')) class SelectionData(): #3. Update the constructor to accept a history array def __init__(self, history): self.slow = SimpleMovingAverage(30) self.fast = SimpleMovingAverage(1) #4. Loop over the history data and update the indicators for bar in history.itertuples(): self.fast.Update(bar.Index[1], bar.close) self.slow.Update(bar.Index[1], bar.close) def is_ready(self): return self.slow.IsReady and self.fast.IsReady def update(self, time, price): self.fast.Update(time, price) self.slow.Update(time, price)