Overall Statistics |
Total Orders 258 Average Win 2.60% Average Loss -1.64% Compounding Annual Return 42.790% Drawdown 17.900% Expectancy 0.497 Start Equity 100000000 End Equity 291135266.42 Net Profit 191.135% Sharpe Ratio 1.367 Sortino Ratio 1.372 Probabilistic Sharpe Ratio 75.371% Loss Rate 42% Win Rate 58% Profit-Loss Ratio 1.58 Alpha 0 Beta 0 Annual Standard Deviation 0.207 Annual Variance 0.043 Information Ratio 1.477 Tracking Error 0.207 Treynor Ratio 0 Total Fees $7891055.25 Estimated Strategy Capacity $34000000.00 Lowest Capacity Asset TSLA UNU3P8Y3WFAD Portfolio Turnover 19.06% |
from AlgorithmImports import * class EldersTripleScreenAlpha(QCAlgorithm): def Initialize(self): ########### Strategy Params ########### self.SetStartDate(2017, 1, 1) self.SetEndDate(2019, 12, 31) self.SetCash(100000000) # Warmup the algorithm with prior data for backtesting self.set_warmup(timedelta(7)) ########### Universe Selection ########### self.UniverseSettings.Resolution = Resolution.HOUR self.AddUniverse(self.CoarseSelectionFunction)#, self.FineSelectionFunction) self.symbols = [] self.data = {} ########### Elders Triple Screen Signals ########### self.ema_period = 20 self.rsi_period = 14 self.macd_fast_period = 12 self.macd_slow_period = 26 self.macd_signal_period = 6 ########### Risk Management Model ########### self.add_risk_management(MaximumDrawdownPercentPerSecurity()) ########### Order Execution Model ########### self.set_execution(VolumeWeightedAveragePriceExecutionModel()) ########### Portfolio Construction Model ########### self.set_portfolio_construction(AccumulativeInsightPortfolioConstructionModel())#rebalance=self.date_rules.week_start("SPY"))) ########### Scheduler ########### # daily trading option #self.schedule.on(self.date_rules.every_day("SPY"), self.time_rules.at(11,30,0, TimeZones.NEW_YORK), self.EvaluateIndicators) ###************* ADD IN MARKET ON CLOSE ORDER HERE****************################# def CoarseSelectionFunction(self, coarse): # Filter to Russell 1000 constituents with a minimum daily trading volume of 500 million selected = [x for x in coarse if x.HasFundamentalData and x.DollarVolume > 500000000\ and 5e6 < x.market_cap] # < 1e10] # Log the top 10 and bottom 10 by dollar volume sorted_selected = sorted(selected, key=lambda x: x.DollarVolume, reverse=True) # Slicing to only return the top 20 to increase concentration and reduce trading frequency top20 = sorted_selected[:20] ############### Evaluate Indicators ######################### ''' Elder's Triple Screen Alpha Logic''' def OnSecuritiesChanged(self, changes): for security in changes.AddedSecurities: symbol = security.Symbol self.data[symbol] = { 'ema': ExponentialMovingAverage(self.ema_period), 'rsi': RelativeStrengthIndex(self.rsi_period, MovingAverageType.Wilders), 'macd': MovingAverageConvergenceDivergence(self.macd_fast_period, self.macd_slow_period, self.macd_signal_period, MovingAverageType.Wilders) } self.RegisterIndicator(symbol, self.data[symbol]['ema'], Resolution.HOUR) self.RegisterIndicator(symbol, self.data[symbol]['rsi'], Resolution.HOUR) self.RegisterIndicator(symbol, self.data[symbol]['macd'], Resolution.Daily) for security in changes.RemovedSecurities: symbol = security.Symbol if symbol in self.data: del self.data[symbol] def EvaluateIndicators(self): for symbol, indicators in self.data.items(): ema = indicators['ema'] rsi = indicators['rsi'] macd = indicators['macd'] if not (ema.IsReady and rsi.IsReady and macd.IsReady): continue ema_value = ema.Current.Value rsi_value = rsi.Current.Value macd_value = macd.Current.Value macd_signal_value = macd.Signal.Current.Value price = self.Securities[symbol].Price direction = InsightDirection.Flat confidence = 0 magnitude = 0 if rsi_value < 30 and macd_value > macd_signal_value: #and price > ema_value: direction = InsightDirection.Up confidence = (70 - rsi_value) / 100 magnitude = macd_value - macd_signal_value elif rsi_value > 70 or macd_value < macd_signal_value:# or price < ema_value: direction = InsightDirection.Down confidence = (rsi_value - 30) / 100 magnitude = macd_signal_value - macd_value insight = Insight.Price(symbol, timedelta(days=1), direction, magnitude, confidence) #self.EmitInsights(insight) #self.Debug(f"Generated Insight: {insight}") if confidence > 0.55: self.emit_insights(insight) self.Debug(f"Generated Insight: {insight}") return insight def OnData(self, data): pass ''' if not self.Portfolio.Invested: return ###### Max Security Weight ###### # Calculate the target weight for each security (e.g., 5%) target_weight = 0.05 # Get the symbols of the invested securities invested_symbols = [x.Symbol for x in self.Portfolio.Values if x.Invested] # Loop through each invested security for symbol in invested_symbols: if symbol in data: bar = data[symbol] if bar is not None: security = self.Portfolio[symbol] # Calculate the current weight of the security in the portfolio if bar.Close is not None: current_weight = security.Quantity * bar.Close / self.Portfolio.TotalPortfolioValue # If the current weight exceeds the target weight, trim the position if current_weight > target_weight: # Calculate the amount to trim trim_amount = (current_weight - target_weight) * self.Portfolio.TotalPortfolioValue # Reduce the position to maintain the target weight self.SetHoldings(symbol, target_weight) self.Debug(f"Reduced position for {symbol} to maintain 5% weight, amount: {trim_amount}") ###### Sell Orders ###### # Iterate through portfolio holdings and check for securities to sell for security in self.Portfolio.Values: symbol = security.Symbol if security.Invested and symbol not in invested_symbols: # Security is invested but not in the current universe, sell it self.Debug(symbol, "Invalid sell order: Security not in current universe") self.Debug(f"Invalid sell order: Sold {symbol} as it's not in the current universe") ###### Buy Orders ###### # Check available buying power before submitting orders for kvp in data.Bars: symbol = kvp.Key bar = kvp.Value # Calculate the order size based on available buying power available_buying_power = self.Portfolio.Cash if available_buying_power <= 0: return # Skip if there's no buying power price = bar.Close quantity = int(available_buying_power / price) # Submit the order only if there's sufficient buying power if quantity > 0: self.SetHoldings(symbol, 0.05) self.Debug(f"Order placed for {symbol}: Quantity={quantity}, Price={price}, TotalValue={quantity*price}") else: self.Debug(f"Not enough buying power to place order for {symbol}") '''
from AlgorithmImports import * from symbol_calcs import * class EldersTripleScreenAlpha(QCAlgorithm): def Initialize(self): ''' Initial Algo parameters and QuantConnect methods''' ########### Strategy Params ########### self.SetStartDate(2017, 1, 1) self.SetEndDate(2019, 12, 31) # Out of Sample (OoS) testing date #self.SetEndDate(2024, 3, 31) self.SetCash(100000) # Define boolean for trading permission for the algorithm. Stops it from trading until the next trading period. #self.tradingperm = True # Warmup the algorithm with prior data for backtesting self.set_warmup(timedelta(30)) ########### Universe Selection ########### self.universe_settings.resolution = Resolution.HOUR self.universe_settings.leverage = 2 #self.add_universe(self.CoarseFilter) self.add_universe(self._fundamental_selection_function) # Variables for universe selection model self.coarse_count = 10 self.averages = { } self.symbols = [] self.data = {} ''' ########### Elders Triple Screen Signals ########### self.ema_period = int(self.get_parameter("ema_period")) self.rsi_period = int(self.get_parameter("rsi_period")) self.macd_fast_period = int(self.get_parameter("macd_period")) self.macd_slow_period = int(self.macd_fast_period*2) self.macd_signal_period = int(self.macd_fast_period/2) ''' ########### Elders Triple Screen Signals ########### self.ema_period = 20 self.rsi_period = 14 self.macd_fast_period = 12 self.macd_slow_period = 26 self.macd_signal_period = 6 ########### Risk Management Model ########### self.add_risk_management(MaximumDrawdownPercentPerSecurity(0.05)) ########### Order Execution Model ########### #self.set_execution(ImmediateExecutionModel()) # VWAP Execution Model, to later be changed to the EMA Model self.set_execution(VolumeWeightedAveragePriceExecutionModel()) ########### Portfolio Construction Model ########### #self.set_portfolio_construction(AccumulativeInsightPortfolioConstructionModel())#rebalance=self.date_rules.week_start("SPY"))) #self.set_portfolio_construction(EqualWeightingPortfolioConstructionModel(rebalance=timedelta(7), portfolioBias=PortfolioBias.LONG)) #self.set_portfolio_construction(EqualWeightingPortfolioConstructionModel(portfolioBias=PortfolioBias.LONG)) self.set_portfolio_construction(RiskParityPortfolioConstructionModel(portfolioBias=PortfolioBias.LONG)) #self.settings.rebalance_portfolio_on_insight_changes = False # Required portfolio free cash value self.Settings.FreePortfolioValuePercentage=0.05 ########### Reality Modeling Parameters ########### # Brokerage Simulation self.set_brokerage_model(BrokerageName.INTERACTIVE_BROKERS_BROKERAGE, AccountType.MARGIN) # Risk Free Interest Rate Modeling self.set_risk_free_interest_rate_model(InterestRateProvider()) # Margin Call Modeling self.portfolio.margin_call_model = DefaultMarginCallModel(self.portfolio, self.default_order_properties) ########### Scheduler ########### # Run 30 mins after open to collect signals # Schedule insight generation every 4 hours #self.schedule.on(self.date_rules.every_day("SPY"), self.time_rules.every(timedelta(minutes=90)), self.EvaluateIndicators) # daily trading option self.schedule.on(self.date_rules.every_day("SPY"), self.time_rules.at(11,30,0, TimeZones.NEW_YORK), self.EvaluateIndicators) def _fundamental_selection_function(self, fundamental: List[Fundamental]) -> List[Symbol]: ''' Fundamental Filter to produce a list of securities within the universe''' filtered = [f for f in fundamental if f.price > 10 and f.has_fundamental_data and not np.isnan(f.valuation_ratios.pe_ratio)] sorted_by_dollar_volume = sorted(filtered, key=lambda f: f.dollar_volume, reverse=True)[:100] sorted_by_pe_ratio = sorted(sorted_by_dollar_volume, key=lambda f: f.valuation_ratios.pe_ratio, reverse=False)[:20] return [f.symbol for f in sorted_by_pe_ratio] def FineFilter(self, fine): ''' Placeholder for further filtering of the universe ''' pass ''' Simpler changes to universe # this event fires whenever we have changes to our universe def on_securities_changed(self, changes): # liquidate removed securities for security in changes.removed_securities: if security.invested: self.liquidate(security.symbol) self.Debug(f"Liquidated {security.symbol}") # we want 20% allocation in each security in our universe - This gives 10% allocation for security in changes.added_securities: self.set_holdings(security.symbol, 0.1) self.Debug(f"Bought {security.symbol}") ''' ############### Evaluate Indicators ######################### ''' Elder's Triple Screen Alpha Logic''' def OnSecuritiesChanged(self, changes): ''' Add indicators whenever securities are added to or removed from the universe''' for security in changes.AddedSecurities: symbol = security.Symbol self.data[symbol] = { 'ema': ExponentialMovingAverage(self.ema_period), 'rsi': RelativeStrengthIndex(self.rsi_period, MovingAverageType.Wilders), 'macd': MovingAverageConvergenceDivergence(self.macd_fast_period, self.macd_slow_period, self.macd_signal_period, MovingAverageType.Wilders) } self.RegisterIndicator(symbol, self.data[symbol]['ema'], Resolution.HOUR) self.RegisterIndicator(symbol, self.data[symbol]['rsi'], Resolution.HOUR) self.RegisterIndicator(symbol, self.data[symbol]['macd'], Resolution.Daily) # Reality Modeling for slippage #security.set_slippage_model(VolumeShareSlippageModel(0.025, 0.1)) #security.set_slippage_model(MarketImpactSlippageModel(self)) for security in changes.RemovedSecurities: symbol = security.Symbol if symbol in self.data: del self.data[symbol] def EvaluateIndicators(self): ''' Evaluate the indicators for the securities ''' # Maybe change this self.data.items() to something else. Rn its not iterating through all the securities like it should for symbol, indicators in self.data.items(): ema = indicators['ema'] rsi = indicators['rsi'] macd = indicators['macd'] if not (ema.IsReady and rsi.IsReady and macd.IsReady): continue ema_value = ema.Current.Value rsi_value = rsi.Current.Value macd_value = macd.Current.Value macd_signal_value = macd.Signal.Current.Value price = self.Securities[symbol].Price direction = InsightDirection.Flat confidence = 0 magnitude = 0 if rsi_value < 30 and macd_value > macd_signal_value: #and price > ema_value: direction = InsightDirection.Up confidence = (70 - rsi_value) / 100 magnitude = macd_value - macd_signal_value # Consider changing this to an AND inistead of an or, since both need to be satisfied elif rsi_value > 70 or macd_value < macd_signal_value:# or price < ema_value: direction = InsightDirection.Down confidence = (rsi_value - 30) / 100 magnitude = macd_signal_value - macd_value insight = Insight.Price(symbol, timedelta(days=1), direction, magnitude, confidence) #self.EmitInsights(insight) #self.Debug(f"Generated Insight: {insight}") if confidence > 0.2: self.emit_insights(insight) self.Debug(f"Generated Insight: {insight}") return insight
from AlgorithmImports import * from symbol_calcs import * class EldersTripleScreenAlpha(QCAlgorithm): def Initialize(self): ########### Strategy Params ########### self.SetStartDate(2017, 1, 1) #self.SetEndDate(2019, 12, 31) self.SetEndDate(2024, 3, 31) self.SetCash(100000) # Define boolean for trading permission for the algorithm. Stops it from trading until the next trading period. #self.tradingperm = True # Warmup the algorithm with prior data for backtesting self.set_warmup(timedelta(30)) ########### Universe Selection ########### self.universe_settings.resolution = Resolution.HOUR self.universe_settings.leverage = 2 #self.add_universe(self.CoarseFilter) self.add_universe(self._fundamental_selection_function) # Variables for universe selection model self.coarse_count = 10 self.averages = { } self.symbols = [] self.data = {} ''' ########### Elders Triple Screen Signals ########### self.ema_period = int(self.get_parameter("ema_period")) self.rsi_period = int(self.get_parameter("rsi_period")) self.macd_fast_period = int(self.get_parameter("macd_period")) self.macd_slow_period = int(self.macd_fast_period*2) self.macd_signal_period = int(self.macd_fast_period/2) ''' ########### Elders Triple Screen Signals ########### self.ema_period = 20 self.rsi_period = 14 self.macd_fast_period = 12 self.macd_slow_period = 26 self.macd_signal_period = 6 ########### Risk Management Model ########### self.add_risk_management(MaximumDrawdownPercentPerSecurity(0.05)) ########### Order Execution Model ########### self.set_execution(ImmediateExecutionModel()) ########### Portfolio Construction Model ########### #self.set_portfolio_construction(AccumulativeInsightPortfolioConstructionModel())#rebalance=self.date_rules.week_start("SPY"))) #self.set_portfolio_construction(EqualWeightingPortfolioConstructionModel(rebalance=timedelta(7), portfolioBias=PortfolioBias.LONG)) #self.set_portfolio_construction(EqualWeightingPortfolioConstructionModel(portfolioBias=PortfolioBias.LONG)) self.set_portfolio_construction(RiskParityPortfolioConstructionModel(portfolioBias=PortfolioBias.LONG)) #self.settings.rebalance_portfolio_on_insight_changes = False # Required portfolio free cash value self.Settings.FreePortfolioValuePercentage=0.05 ########### Reality Modeling Parameters ########### # Brokerage Simulation self.set_brokerage_model(BrokerageName.INTERACTIVE_BROKERS_BROKERAGE, AccountType.MARGIN) # Risk Free Interest Rate Modeling self.set_risk_free_interest_rate_model(InterestRateProvider()) # Margin Call Modeling self.portfolio.margin_call_model = DefaultMarginCallModel(self.portfolio, self.default_order_properties) ########### Scheduler ########### # Run 30 mins after open to collect signals # Schedule insight generation every 4 hours #self.schedule.on(self.date_rules.every_day("SPY"), self.time_rules.every(timedelta(minutes=90)), self.EvaluateIndicators) # daily trading option self.schedule.on(self.date_rules.every_day("SPY"), self.time_rules.at(11,30,0, TimeZones.NEW_YORK), self.EvaluateIndicators) def _fundamental_selection_function(self, fundamental: List[Fundamental]) -> List[Symbol]: ''' Fundamental Filter to produce a list of securities within the universe''' filtered = [f for f in fundamental if f.price > 10 and f.has_fundamental_data and not np.isnan(f.valuation_ratios.pe_ratio)] sorted_by_dollar_volume = sorted(filtered, key=lambda f: f.dollar_volume, reverse=True)[:100] sorted_by_pe_ratio = sorted(sorted_by_dollar_volume, key=lambda f: f.valuation_ratios.pe_ratio, reverse=False)[:20] return [f.symbol for f in sorted_by_pe_ratio] def FineFilter(self, fine): ''' Plaseholder for further filtering of the universe ''' pass ''' Simpler changes to universe # this event fires whenever we have changes to our universe def on_securities_changed(self, changes): # liquidate removed securities for security in changes.removed_securities: if security.invested: self.liquidate(security.symbol) self.Debug(f"Liquidated {security.symbol}") # we want 20% allocation in each security in our universe - This gives 10% allocation for security in changes.added_securities: self.set_holdings(security.symbol, 0.1) self.Debug(f"Bought {security.symbol}") ''' ############### Evaluate Indicators ######################### ''' Elder's Triple Screen Alpha Logic''' def OnSecuritiesChanged(self, changes): ''' Add indicators whenever securities are added to or removed from the universe''' for security in changes.AddedSecurities: symbol = security.Symbol self.data[symbol] = { 'ema': ExponentialMovingAverage(self.ema_period), 'rsi': RelativeStrengthIndex(self.rsi_period, MovingAverageType.Wilders), 'macd': MovingAverageConvergenceDivergence(self.macd_fast_period, self.macd_slow_period, self.macd_signal_period, MovingAverageType.Wilders) } self.RegisterIndicator(symbol, self.data[symbol]['ema'], Resolution.HOUR) self.RegisterIndicator(symbol, self.data[symbol]['rsi'], Resolution.HOUR) self.RegisterIndicator(symbol, self.data[symbol]['macd'], Resolution.Daily) # Reality Modeling for slippage security.set_slippage_model(VolumeShareSlippageModel(0.025, 0.1)) for security in changes.RemovedSecurities: symbol = security.Symbol if symbol in self.data: del self.data[symbol] def EvaluateIndicators(self): ''' Evaluate the indicators for the securities ''' # Maybe change this self.data.items() to something else. Rn its not iterating through all the securities like it should for symbol, indicators in self.data.items(): ema = indicators['ema'] rsi = indicators['rsi'] macd = indicators['macd'] if not (ema.IsReady and rsi.IsReady and macd.IsReady): continue ema_value = ema.Current.Value rsi_value = rsi.Current.Value macd_value = macd.Current.Value macd_signal_value = macd.Signal.Current.Value price = self.Securities[symbol].Price direction = InsightDirection.Flat confidence = 0 magnitude = 0 # Requires both to be true to be conservative and only enter positions where we are reasonably certain its a good time if rsi_value < 30 and macd_value > macd_signal_value: #and price > ema_value: direction = InsightDirection.Up confidence = (70 - rsi_value) / 100 magnitude = macd_value - macd_signal_value # Uses or instead of and to be more conservative and exit faster, where if one of the signals is below then liquidate. elif rsi_value > 70 or macd_value < macd_signal_value:# or price < ema_value: direction = InsightDirection.Down confidence = (rsi_value - 30) / 100 magnitude = macd_signal_value - macd_value insight = Insight.Price(symbol, timedelta(days=1), direction, magnitude, confidence) #self.EmitInsights(insight) #self.Debug(f"Generated Insight: {insight}") if confidence > 0.2: self.emit_insights(insight) self.Debug(f"Generated Insight: {insight}") return insight
from AlgorithmImports import * #from symbol_calcs import * class EldersTripleScreenAlpha(QCAlgorithm): def Initialize(self): ########### Strategy Params ########### self.SetStartDate(2017, 1, 1) self.SetEndDate(2019, 12, 31) self.SetCash(100000) # Define boolean for trading permission for the algorithm. Stops it from trading until the next trading period. #self.tradingperm = True # Warmup the algorithm with prior data for backtesting #self.set_warmup(timedelta(7)) self.set_warmup(30) ########### Universe Selection ########### self.universe_settings.resolution = Resolution.MINUTE self.universe_settings.leverage = 2 #self.add_universe(self.CoarseFilter) self.add_universe(self._fundamental_selection_function) # Variables for universe selection model self.coarse_count = 10 self.averages = { } self.symbols = [] self.data = {} ########### Elders Triple Screen Signals ########### self.ema_period = int(self.get_parameter("ema_period")) self.rsi_period = int(self.get_parameter("rsi_period")) self.macd_fast_period = int(self.get_parameter("macd_period")) self.macd_slow_period = int(self.macd_fast_period*2) self.macd_signal_period = int(self.macd_fast_period/2) ########### Risk Management Model ########### self.add_risk_management(MaximumDrawdownPercentPerSecurity(0.10)) ########### Order Execution Model ########### self.set_execution(ImmediateExecutionModel()) ########### Portfolio Construction Model ########### #self.set_portfolio_construction(AccumulativeInsightPortfolioConstructionModel())#rebalance=self.date_rules.week_start("SPY"))) self.set_portfolio_construction(EqualWeightingPortfolioConstructionModel()) #self.set_portfolio_construction(AccumulativeInsightPortfolioConstructionModel()) self.Settings.FreePortfolioValuePercentage=0.05 ########### Scheduler ########### # Run 30 mins after open to collect signals # Schedule insight generation every 4 hours #self.schedule.on(self.date_rules.every_day("SPY"), self.time_rules.every(timedelta(minutes=180)), self.EvaluateIndicators) # daily trading option self.schedule.on(self.date_rules.every_day("SPY"), self.time_rules.at(11,30,0, TimeZones.NEW_YORK), self.EvaluateIndicators) ########## Alpha Models ############ ''' self.add_alpha(self.EvaluateEMA()) self.add_alpha(self.EvaluateRSI()) self.add_alpha(self.EvaluateMACD()) ''' def _fundamental_selection_function(self, fundamental: List[Fundamental]) -> List[Symbol]: filtered = [f for f in fundamental if f.price > 10 and f.has_fundamental_data and not np.isnan(f.valuation_ratios.pe_ratio)] sorted_by_dollar_volume = sorted(filtered, key=lambda f: f.dollar_volume, reverse=True)[:100] sorted_by_pe_ratio = sorted(sorted_by_dollar_volume, key=lambda f: f.valuation_ratios.pe_ratio, reverse=False)[:self.coarse_count] return [f.symbol for f in sorted_by_pe_ratio] def FineFilter(self, fine): pass ''' Simpler changes to universe ''' # this event fires whenever we have changes to our universe def on_securities_changed(self, changes): # liquidate removed securities for security in changes.removed_securities: if security.invested: self.liquidate(security.symbol) self.Debug(f"Liquidated {security.symbol}") # we want 20% allocation in each security in our universe - This gives 10% allocation for security in changes.added_securities: self.set_holdings(security.symbol, 0.1) self.Debug(f"Bought {security.symbol}") ############### Evaluate Indicators ######################### ''' Elder's Triple Screen Alpha Logic''' ''' Simpler combined method for insights. Either keep these seperate or consolidate into a "Momentum" indicator ''' def EvaluateIndicators(self): for symbol, indicators in self.data.items(): ema = indicators['ema'] rsi = indicators['rsi'] macd = indicators['macd'] if not (ema.IsReady and rsi.IsReady and macd.IsReady): continue ema_value = ema.Current.Value rsi_value = rsi.Current.Value macd_value = macd.Current.Value macd_signal_value = macd.Signal.Current.Value price = self.Securities[symbol].Price direction = InsightDirection.Flat confidence = 0 magnitude = 0 if rsi_value < 45 or macd_value > macd_signal_value: #and price > ema_value: direction = InsightDirection.Up confidence = (70 - rsi_value) / 100 magnitude = macd_value - macd_signal_value elif rsi_value > 70 and macd_value < macd_signal_value:# or price < ema_value: direction = InsightDirection.Down confidence = (rsi_value - 30) / 100 magnitude = macd_signal_value - macd_value insight = Insight.Price(symbol, timedelta(days=1), direction, magnitude, confidence) #self.EmitInsights(insight) #self.Debug(f"Generated Insight: {insight}") if confidence > 0.55: self.emit_insights(insight) self.Debug(f"Generated Insight: {insight}") return insight
from AlgorithmImports import * #from symbol_calcs import * class EldersTripleScreenAlpha(QCAlgorithm): def Initialize(self): ########### Strategy Params ########### self.SetStartDate(2017, 1, 1) self.SetEndDate(2019, 12, 31) self.SetCash(100000) # Define boolean for trading permission for the algorithm. Stops it from trading until the next trading period. #self.tradingperm = True # Warmup the algorithm with prior data for backtesting #self.set_warmup(timedelta(7)) self.set_warmup(30) ########### Universe Selection ########### self.universe_settings.resolution = Resolution.MINUTE self.universe_settings.leverage = 2 #self.add_universe(self.CoarseFilter) self.add_universe(self._fundamental_selection_function) # Variables for universe selection model self.coarse_count = 10 self.averages = { } self.symbols = [] self.data = {} ########### Elders Triple Screen Signals ########### self.ema_period = int(self.get_parameter("ema_period")) self.rsi_period = int(self.get_parameter("rsi_period")) self.macd_fast_period = int(self.get_parameter("macd_period")) self.macd_slow_period = int(self.macd_fast_period*2) self.macd_signal_period = int(self.macd_fast_period/2) ########### Risk Management Model ########### self.add_risk_management(MaximumDrawdownPercentPerSecurity(0.10)) ########### Order Execution Model ########### self.set_execution(ImmediateExecutionModel()) ########### Portfolio Construction Model ########### #self.set_portfolio_construction(AccumulativeInsightPortfolioConstructionModel())#rebalance=self.date_rules.week_start("SPY"))) self.set_portfolio_construction(EqualWeightingPortfolioConstructionModel()) #self.set_portfolio_construction(AccumulativeInsightPortfolioConstructionModel()) self.Settings.FreePortfolioValuePercentage=0.05 ########### Scheduler ########### # Run 30 mins after open to collect signals # Schedule insight generation every 4 hours #self.schedule.on(self.date_rules.every_day("SPY"), self.time_rules.every(timedelta(minutes=180)), self.EvaluateIndicators) # daily trading option self.schedule.on(self.date_rules.every_day("SPY"), self.time_rules.at(11,30,0, TimeZones.NEW_YORK), self.EvaluateIndicators) ########## Alpha Models ############ ''' self.add_alpha(self.EvaluateEMA()) self.add_alpha(self.EvaluateRSI()) self.add_alpha(self.EvaluateMACD()) ''' def _fundamental_selection_function(self, fundamental: List[Fundamental]) -> List[Symbol]: filtered = [f for f in fundamental if f.price > 10 and f.has_fundamental_data and not np.isnan(f.valuation_ratios.pe_ratio)] sorted_by_dollar_volume = sorted(filtered, key=lambda f: f.dollar_volume, reverse=True)[:100] sorted_by_pe_ratio = sorted(sorted_by_dollar_volume, key=lambda f: f.valuation_ratios.pe_ratio, reverse=False)[:self.coarse_count] return [f.symbol for f in sorted_by_pe_ratio] def FineFilter(self, fine): pass ''' Simpler changes to universe ''' # this event fires whenever we have changes to our universe def on_securities_changed(self, changes): # liquidate removed securities for security in changes.removed_securities: if security.invested: self.liquidate(security.symbol) self.Debug(f"Liquidated {security.symbol}") # we want 20% allocation in each security in our universe - This gives 10% allocation for security in changes.added_securities: self.set_holdings(security.symbol, 0.1) self.Debug(f"Bought {security.symbol}") ############### Evaluate Indicators ######################### ''' Elder's Triple Screen Alpha Logic''' ''' Simpler combined method for insights. Either keep these seperate or consolidate into a "Momentum" indicator ''' def EvaluateIndicators(self): for symbol, indicators in self.data.items(): ema = indicators['ema'] rsi = indicators['rsi'] macd = indicators['macd'] if not (ema.IsReady and rsi.IsReady and macd.IsReady): continue ema_value = ema.Current.Value rsi_value = rsi.Current.Value macd_value = macd.Current.Value macd_signal_value = macd.Signal.Current.Value price = self.Securities[symbol].Price direction = InsightDirection.Flat confidence = 0 magnitude = 0 if rsi_value < 45 or macd_value > macd_signal_value: #and price > ema_value: direction = InsightDirection.Up confidence = (70 - rsi_value) / 100 magnitude = macd_value - macd_signal_value elif rsi_value > 70 and macd_value < macd_signal_value:# or price < ema_value: direction = InsightDirection.Down confidence = (rsi_value - 30) / 100 magnitude = macd_signal_value - macd_value insight = Insight.Price(symbol, timedelta(days=1), direction, magnitude, confidence) #self.EmitInsights(insight) #self.Debug(f"Generated Insight: {insight}") if confidence > 0.55: self.emit_insights(insight) self.Debug(f"Generated Insight: {insight}") return insight
from AlgorithmImports import * from symbol_calcs import * class EldersTripleScreenAlpha(QCAlgorithm): def Initialize(self): ''' Initial Algo parameters and QuantConnect methods''' ########### Strategy Params ########### self.SetStartDate(2017, 1, 1) self.SetEndDate(2019, 12, 31) # Out of Sample (OoS) testing date #self.SetEndDate(2024, 3, 31) #self.SetCash(100000) self.SetCash(100000000) # Define boolean for trading permission for the algorithm. Stops it from trading until the next trading period. #self.tradingperm = True # Warmup the algorithm with prior data for backtesting self.set_warmup(timedelta(30)) ########### Universe Selection ########### self.universe_settings.resolution = Resolution.HOUR self.universe_settings.leverage = 2 #self.add_universe(self.CoarseFilter) self.add_universe(self._fundamental_selection_function) # Variables for universe selection model self.coarse_count = 10 self.averages = { } self.symbols = [] self.data = {} ''' ########### Elders Triple Screen Signals ########### self.ema_period = int(self.get_parameter("ema_period")) self.rsi_period = int(self.get_parameter("rsi_period")) self.macd_fast_period = int(self.get_parameter("macd_period")) self.macd_slow_period = int(self.macd_fast_period*2) self.macd_signal_period = int(self.macd_fast_period/2) ''' ########### Elders Triple Screen Signals ########### self.ema_period = 20 self.rsi_period = 14 self.macd_fast_period = 12 self.macd_slow_period = 26 self.macd_signal_period = 6 ########### Risk Management Model ########### self.add_risk_management(MaximumDrawdownPercentPerSecurity(0.05)) ########### Order Execution Model ########### # Immediat execution model - so trades right at 1130 each day self.set_execution(ImmediateExecutionModel()) # VWAP Execution Model, to later be changed to the EMA Model #self.set_execution(VolumeWeightedAveragePriceExecutionModel()) ########### Portfolio Construction Model ########### #self.set_portfolio_construction(AccumulativeInsightPortfolioConstructionModel())#rebalance=self.date_rules.week_start("SPY"))) #self.set_portfolio_construction(EqualWeightingPortfolioConstructionModel(rebalance=timedelta(7), portfolioBias=PortfolioBias.LONG)) #self.set_portfolio_construction(EqualWeightingPortfolioConstructionModel(portfolioBias=PortfolioBias.LONG)) #self.set_portfolio_construction(RiskParityPortfolioConstructionModel(portfolioBias=PortfolioBias.LONG)) self.set_portfolio_construction(RiskParityPortfolioConstructionModel(portfolioBias=PortfolioBias.LONG)) #self.settings.rebalance_portfolio_on_insight_changes = False # Required portfolio free cash value self.Settings.FreePortfolioValuePercentage=0.05 ########### Reality Modeling Parameters ########### # Brokerage Simulation self.set_brokerage_model(BrokerageName.INTERACTIVE_BROKERS_BROKERAGE, AccountType.MARGIN) # Risk Free Interest Rate Modeling self.set_risk_free_interest_rate_model(InterestRateProvider()) # Margin Call Modeling self.portfolio.margin_call_model = DefaultMarginCallModel(self.portfolio, self.default_order_properties) ########### Scheduler ########### # Run 30 mins after open to collect signals # Schedule insight generation every 4 hours #self.schedule.on(self.date_rules.every_day("SPY"), self.time_rules.every(timedelta(minutes=90)), self.EvaluateIndicators) # daily trading option self.schedule.on(self.date_rules.every_day("SPY"), self.time_rules.at(11,30,0, TimeZones.NEW_YORK), self.EvaluateIndicators) ########### Object Store ########## self.universe_store = '' self.EMA_store = '' self.RSI_store = '' self.MACD_store = '' ########### Load Existing Universe ########### if self.IsLiveEnvironment(): self.LoadExistingUniverse() def IsLiveEnvironment(self): ''' Check if the algorithm is running in a live environment ''' return self.LiveMode def LoadExistingUniverse(self): ''' Load the existing universe from the live brokerage account holdings ''' self.Debug("Loading existing universe from brokerage account...") # Fetch existing holdings holdings = [x.Symbol for x in self.Portfolio.Values if x.Invested] self.Debug(f"Found {len(holdings)} existing holdings.") # Register indicators for the existing holdings for symbol in holdings: self.data[symbol] = { 'ema': ExponentialMovingAverage(self.ema_period), 'rsi': RelativeStrengthIndex(self.rsi_period, MovingAverageType.Wilders), 'macd': MovingAverageConvergenceDivergence(self.macd_fast_period, self.macd_slow_period, self.macd_signal_period, MovingAverageType.Wilders) } self.RegisterIndicator(symbol, self.data[symbol]['ema'], Resolution.HOUR) self.RegisterIndicator(symbol, self.data[symbol]['rsi'], Resolution.HOUR) self.RegisterIndicator(symbol, self.data[symbol]['macd'], Resolution.Daily) return holdings def _fundamental_selection_function(self, fundamental: List[Fundamental]) -> List[Symbol]: ''' Fundamental Filter to produce a list of securities within the universe''' filtered = [f for f in fundamental if f.price > 10 and \ f.has_fundamental_data and \ not np.isnan(f.valuation_ratios.pe_ratio) and \ f.valuation_ratios.forward_pe_ratio > 5 and \ f.market_cap > 500000] self.Debug(f"Filtered securities: {', '.join([f.symbol.Value for f in filtered])}") sorted_by_dollar_volume = sorted(filtered, key=lambda f: f.dollar_volume, reverse=True)[:100] self.Debug(f"Top 100 by dollar volume: {', '.join([f.symbol.Value for f in sorted_by_dollar_volume])}") sorted_by_pe_ratio = sorted(sorted_by_dollar_volume, key=lambda f: f.valuation_ratios.pe_ratio, reverse=False)[:20] self.Debug(f"Final selected securities: {', '.join([f.symbol.Value for f in sorted_by_pe_ratio])}") self.Debug(f"Final selected securities: {sorted_by_pe_ratio[:20]}") return [f.symbol for f in sorted_by_pe_ratio[:20]] def FineFilter(self, fine): ''' Placeholder for further filtering of the universe ''' pass ''' Simpler changes to universe # this event fires whenever we have changes to our universe def on_securities_changed(self, changes): # liquidate removed securities for security in changes.removed_securities: if security.invested: self.liquidate(security.symbol) self.Debug(f"Liquidated {security.symbol}") # we want 20% allocation in each security in our universe - This gives 10% allocation for security in changes.added_securities: self.set_holdings(security.symbol, 0.1) self.Debug(f"Bought {security.symbol}") ''' ############### Evaluate Indicators ######################### ''' Elder's Triple Screen Alpha Logic''' def OnSecuritiesChanged(self, changes): ''' Add indicators whenever securities are added to or removed from the universe''' for security in changes.AddedSecurities: symbol = security.Symbol self.data[symbol] = { 'ema': ExponentialMovingAverage(self.ema_period), 'rsi': RelativeStrengthIndex(self.rsi_period, MovingAverageType.Wilders), 'macd': MovingAverageConvergenceDivergence(self.macd_fast_period, self.macd_slow_period, self.macd_signal_period, MovingAverageType.Wilders) } self.RegisterIndicator(symbol, self.data[symbol]['ema'], Resolution.HOUR) self.RegisterIndicator(symbol, self.data[symbol]['rsi'], Resolution.HOUR) self.RegisterIndicator(symbol, self.data[symbol]['macd'], Resolution.Daily) # Reality Modeling for slippage #security.set_slippage_model(VolumeShareSlippageModel(0.025, 0.1)) #security.set_slippage_model(MarketImpactSlippageModel(self)) for security in changes.RemovedSecurities: symbol = security.Symbol if symbol in self.data: del self.data[symbol] def EvaluateIndicators(self): ''' Evaluate the indicators for the securities ''' # Maybe change this self.data.items() to something else. Rn its not iterating through all the securities like it should for symbol, indicators in self.data.items(): ema = indicators['ema'] rsi = indicators['rsi'] macd = indicators['macd'] if not (ema.IsReady and rsi.IsReady and macd.IsReady): continue ema_value = ema.Current.Value rsi_value = rsi.Current.Value macd_value = macd.Current.Value macd_signal_value = macd.Signal.Current.Value price = self.Securities[symbol].Price direction = InsightDirection.Flat confidence = 0 magnitude = 0 if rsi_value < 30 and macd_value > macd_signal_value: #and price > ema_value: direction = InsightDirection.Up confidence = (70 - rsi_value) / 100 magnitude = macd_value - macd_signal_value # Consider changing this to an AND inistead of an or, since both need to be satisfied elif rsi_value > 70 or macd_value < macd_signal_value:# or price < ema_value: direction = InsightDirection.Down confidence = (rsi_value - 30) / 100 magnitude = macd_signal_value - macd_value insight = Insight.Price(symbol, timedelta(days=1), direction, magnitude, confidence) #self.EmitInsights(insight) #self.Debug(f"Generated Insight: {insight}") if confidence > 0.2: self.emit_insights(insight) self.Debug(f"Generated Insight: {insight}") # Store indicator values in an object #self.plot('EMA', 'Value', self.ema.current.value) #self.EMA_store += f'{self.ema.current.end_time},{self.sma.current.value}\n' #self.RSI_store += f'{self.rsi.current.end_time},{self.rsi.current.value}\n' #self.MACD_store += f'{self.macd.current.end_time},{self.macd.current.value}\n' return insight def on_end_of_algorithm(self): pass #placeholder for now, will infact do clean endings for the algo where it saves the status of all the indicators #self.object_store.save('EMA_values_python', self.EMA_store) #self.object_store.save('RSI_values_python', self.RSI_store) #self.object_store.save('MACD_values_python', self.MACD_store)
#region imports from AlgorithmImports import * #endregion # Note this class was copied from bottom of main.py, it can technically be run seperately as long as the import is there class SymbolData(object): def __init__(self, symbol): self._symbol = symbol self.tolerance = 1.01 self.fast = ExponentialMovingAverage(100) self.slow = ExponentialMovingAverage(300) self.is_uptrend = False self.scale = 1 print("SymbolData Init Complete") def update(self, time, value): if self.fast.update(time, value) and self.slow.update(time, value): fast = self.fast.current.value slow = self.slow.current.value self.is_uptrend = fast > slow * self.tolerance if self.is_uptrend: self.scale = (fast - slow) / ((fast + slow) / 2.0) return print("Update method ran successfully")
#region imports from AlgorithmImports import * #endregion # Your New Python File