Overall Statistics |
Total Trades 2897 Average Win 0.12% Average Loss -0.12% Compounding Annual Return -30.052% Drawdown 50.400% Expectancy -0.287 Net Profit -33.070% Sharpe Ratio -0.282 Probabilistic Sharpe Ratio 4.959% Loss Rate 63% Win Rate 37% Profit-Loss Ratio 0.95 Alpha -0.084 Beta 1.856 Annual Standard Deviation 0.464 Annual Variance 0.216 Information Ratio -0.309 Tracking Error 0.342 Treynor Ratio -0.071 Total Fees $2958.96 Estimated Strategy Capacity $14000000.00 Lowest Capacity Asset MCW XPMG4J9N0TID |
import numpy as np from scipy import stats from collections import deque #region imports from AlgorithmImports import * #endregion from Execution.ImmediateExecutionModel import ImmediateExecutionModel from Portfolio.EqualWeightingPortfolioConstructionModel import EqualWeightingPortfolioConstructionModel class NadionTransdimensionalAutosequencers(QCAlgorithm): def Initialize(self): self.SetStartDate(2021, 10, 1) # Set Start Date self.SetCash(100000) # Set Strategy Cash self.SetBenchmark("SPY") self.UniverseSettings.Leverage = 0 #self.Settings.RebalancePortfolioOnInsightChanges = True #self.Settings.RebalancePortfolioOnSecurityChanges = True self.SetPortfolioConstruction(EqualWeightingPortfolioConstructionModel(lambda time: Expiry.EndOfWeek(time))) self.SetExecution(ImmediateExecutionModel()) self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Margin) #self.SetPortfolioConstruction(EqualWeightingPortfolioConstructionModel()) self.UniverseSettings.Resolution=Resolution.Daily self.SetUniverseSelection( QC500UniverseSelectionModel() ) #self.SetAlpha(MyAlpha()) self.rebalance = self.Time self.securities = [] self.symbol_data_by_symbol = {} self.sorted_mom = [] self.mom_scores = {} self.num_stocks = 30 def OnData(self, data): insight = [] if self.rebalance >= self.Time: return self.mom_scores = {} for k,v in self.symbol_data_by_symbol.items(): #algorithm.Debug(str(repr(v.mom))) if k.Value == 'RIDE': self.Debug(f"{k}: {v.mom.Score}") if v.mom.Score >= 40: self.mom_scores[k] = v.mom.Score #self.Debug(f"{k}: {len(v.mom.queue)}") #self.Debug(f"{k}: {self.mom_scores[k]}") self.sorted_mom = sorted([k for k,v in self.mom_scores.items()], key=lambda x: self.mom_scores[x], reverse=True) self.selected = self.sorted_mom[:self.num_stocks] for security in self.selected: insight += [(Insight.Price(security, Expiry.EndOfWeek, InsightDirection.Up))] #self.Debug(f"{algorithm.Time}:update insights") self.rebalance = Expiry.EndOfWeek(self.Time) self.EmitInsights(insight) def OnSecuritiesChanged(self, changes): #algorithm.Debug(f"{algorithm.Time}:security changes called") #algorithm.Debug(f"removed: {len(changes.RemovedSecurities)}") #algorithm.Debug(f"added: {len(changes.AddedSecurities)}") for security in changes.AddedSecurities: self.symbol_data_by_symbol[security.Symbol] = SymbolData(self, security.Symbol) #algorithm.Debug(f"{algorithm.Time}: Added {security.Symbol}") for security in changes.RemovedSecurities: if security.Symbol in self.symbol_data_by_symbol: symbol_data = self.symbol_data_by_symbol.pop(security.Symbol, None) if symbol_data: symbol_data.dispose() #algorithm.Debug(f"{algorithm.Time}: Removed {security.Symbol}") if security in self.securities: self.securities.remove(security) self.securities.extend(changes.AddedSecurities) for security in self.securities: if security.Symbol not in self.ActiveSecurities: self.Debug(f"{security} not in active but is in self") self.securities.remove(security) symbol_data = self.symbol_data_by_symbol.pop(security.Symbol, None) if symbol_data: symbol_data.dispose() self.Debug(f"{security.Symbol} data removed") class SymbolData: def __init__(self, algorithm, symbol): self.algorithm = algorithm self.symbol = symbol self.mom = CustomMomentum("momentum", 125) self.consolidator = TradeBarConsolidator(1) algorithm.SubscriptionManager.AddConsolidator(symbol, self.consolidator) algorithm.RegisterIndicator(symbol, self.mom, self.consolidator) algorithm.WarmUpIndicator(self.symbol, self.mom) def dispose(self): self.algorithm.SubscriptionManager.RemoveConsolidator(self.symbol, self.consolidator) class CustomMomentum(PythonIndicator): def __init__(self, name, period): self.Name = name self.WarmUpPeriod = period self.Time = datetime.min self.Value = 0 self.Score = 0 self.queue = deque(maxlen=period) def __repr__(self): return "{0} -> IsReady: {1}. Time: {2}. Value: {3}".format(self.Name, self.IsReady, self.Time, self.Score) def Update(self, input: BaseData) -> bool: self.queue.appendleft(input.Value) x = np.arange(len(self.queue)) log_ts = np.log(self.queue) slope, intercept, r_value, p_value, std_err = stats.linregress(x, log_ts) annualized_slope = (np.power(np.exp(slope), 252) - 1) * 100 self.Time = input.Time self.Score = annualized_slope * (r_value**2) return x == self.queue.maxlen ''' class MyAlpha(AlphaModel): def __init__(self): self.securities = [] self.symbol_data_by_symbol = {} self.sorted_mom = [] self.mom_scores = {} self.num_stocks = 30 def Update(self, algorithm, data): insight = [] if self.rebalance >= self.Time: return for k,v in self.symbol_data_by_symbol.items(): #algorithm.Debug(str(repr(v.mom))) if not v.mom.IsReady: return if v.mom.Score >= 40: self.mom_scores[k] = v.mom.Score # algorithm.Debug(f"{k}: {v.mom.Score}") self.sorted_mom = sorted([k for k,v in self.mom_scores.items()], key=lambda x: self.mom_scores[x], reverse=True) self.selected = self.sorted_mom[:self.num_stocks] for security in self.selected: insight += [(Insight.Price(security, timedelta(days = 1), InsightDirection.Up))] #algorithm.Debug(f"{algorithm.Time}:update insights") self.rebalance = Expiry.EndOfMonth(self.Time) return insight '''