Overall Statistics |
Total Orders 0 Average Win 0% Average Loss 0% Compounding Annual Return 0% Drawdown 0% Expectancy 0 Start Equity 100000 End Equity 100000 Net Profit 0% Sharpe Ratio 0 Sortino Ratio 0 Probabilistic Sharpe Ratio 0% Loss Rate 0% Win Rate 0% Profit-Loss Ratio 0 Alpha 0 Beta 0 Annual Standard Deviation 0 Annual Variance 0 Information Ratio -1.947 Tracking Error 0.104 Treynor Ratio 0 Total Fees $0.00 Estimated Strategy Capacity $0 Lowest Capacity Asset Portfolio Turnover 0% |
from AlgorithmImports import * class MarketSentimentAlgorithm(QCAlgorithm): def Initialize(self): self.SetStartDate(2024, 1, 1) self.SetEndDate(2024, 12, 31) self.SetCash(100000) self.UniverseSettings.Resolution = Resolution.Daily self.AddUniverse(self.CoarseSelectionFunction) # Sentiment variables self.ad_line = 0 self.total_sentiment_score = 0 # Dictionary to hold SMA indicators self.sma_indicators = {} # Log control self.max_logs_per_day = 50 self.current_log_count = 0 self.last_log_date = self.Time.date() # Initialize plots self.Plot("Sentiment", "Market Sentiment", 0) self.Plot("Indicators", "A/D Line", 0) self.Plot("Indicators", "A/D Ratio", 0) self.Plot("Indicators", "TRIN", 0) self.Plot("Indicators", "% Above MA", 0) self.Plot("Indicators", "Volume Breadth", 0) """ Plot Descriptions: 1. Sentiment - Market Sentiment: - **Description**: This plot represents the composite sentiment score derived from multiple market indicators, including the Advance/Decline Ratio (A/D Ratio), Percentage of Stocks Above 50-Day Moving Average (% Above MA), and the TRIN (Arms Index). - **Calculation**: - **A/D Ratio**: Calculated as the ratio of advancing stocks to declining stocks. A higher ratio indicates more stocks are advancing compared to declining. - **% Above MA**: Represents the percentage of stocks trading above their 50-day Simple Moving Average (SMA). A higher percentage suggests a majority of stocks are in an upward trend. - **TRIN**: The TRIN Index is calculated as the ratio of the A/D Ratio to the Volume Breadth (difference between advancing and declining volumes). It provides insights into market pressure and investor sentiment. - **Composite Sentiment Score**: Combines the normalized values of the above indicators using weighted factors (e.g., 0.4 for A/D Ratio, 0.4 for % Above MA, and 0.2 for TRIN) to produce a single sentiment score ranging between -1 and 1. - **Purpose**: - **Overall Market Sentiment**: Provides a unified measure of the market's bullish or bearish sentiment based on breadth indicators. - **Trend Identification**: Helps in identifying prevailing market trends and potential reversals by analyzing the combined signals from multiple indicators. - **Decision-Making**: Assists in making informed trading decisions by offering a consolidated view of market health and momentum. - **Interpretation**: - **Positive Sentiment Score**: Indicates a bullish market sentiment where the majority of stocks are advancing, and more volume is supporting upward movements. - **Negative Sentiment Score**: Reflects a bearish market sentiment with more declining stocks and higher volume on the downside. - **Neutral Range**: Scores around zero suggest a balanced market with no clear bullish or bearish dominance. - **Usage in Strategy**: - **Entry and Exit Signals**: Utilize the sentiment score to determine optimal points for entering or exiting positions based on prevailing market conditions. - **Risk Management**: Adjust position sizing or implement hedging strategies in response to significant shifts in market sentiment. - **Confirmation Tool**: Use the sentiment score in conjunction with other technical or fundamental indicators to validate trading signals. - **Visualization Enhancements**: - **Threshold Lines**: Incorporate horizontal lines at key sentiment score levels (e.g., -0.5, 0, +0.5) to quickly identify overbought or oversold conditions. - **Color Coding**: Apply color gradients to the sentiment score plot to visually distinguish between bullish (e.g., green), bearish (e.g., red), and neutral (e.g., gray) sentiments. - **Annotations**: Add markers or annotations for significant sentiment score changes to highlight potential trading opportunities or risks. - **Benefits**: - **Holistic View**: Combines multiple indicators into a single metric, simplifying the analysis of market conditions. - **Dynamic Adaptation**: Adjusts to changing market environments by reflecting real-time sentiment shifts. - **Enhanced Clarity**: Facilitates easier interpretation and quicker decision-making through a consolidated sentiment measure. 2. Indicators - A/D Line: - **Description**: The Advance/Decline Line, a cumulative indicator that sums the difference between advancing and declining stocks. - **Purpose**: Measures the breadth of the market, showing the net number of advancing versus declining stocks over time. - **Usage**: An upward trend indicates increasing market strength, whereas a downward trend suggests weakening market conditions. 3. Indicators - A/D Ratio: - **Description**: The ratio of advancing stocks to declining stocks. - **Purpose**: Provides a quick snapshot of market sentiment by comparing the number of advancing stocks against declining ones. - **Usage**: Ratios above 1 indicate more advancing stocks, signaling bullish sentiment. Ratios below 1 suggest bearish sentiment. 4. Indicators - TRIN: - **Description**: The TRIN (Arms Index), calculated as the ratio of the A/D Ratio to the Volume Breadth. - **Purpose**: Combines market breadth and volume to assess overall market pressure and investor sentiment. - **Usage**: Values below 1 typically indicate bullish sentiment, while values above 1 suggest bearish sentiment. 5. Indicators - % Above MA: - **Description**: The percentage of stocks trading above their 50-day Simple Moving Average (SMA). - **Purpose**: Measures the overall market trend by determining the proportion of stocks in an uptrend. - **Usage**: Higher percentages indicate a majority of stocks are in an uptrend, signaling bullish market conditions. Lower percentages suggest a bearish trend. 6. Indicators - Volume Breadth: - **Description**: The difference between advancing and declining volumes. - **Purpose**: Assesses the strength behind market movements by comparing the volume of advancing stocks against declining ones. - **Usage**: Positive values indicate more volume in advancing stocks, reinforcing bullish sentiment. Negative values point to stronger volume in declining stocks, supporting bearish sentiment. """ def CoarseSelectionFunction(self, coarse): # Enhanced Filtering: # 1. Has Fundamental Data # 2. Security Type is Equity # 3. Dollar Volume > $1,000,000 # 4. Symbol does not contain spaces filtered = [ x for x in coarse if x.HasFundamentalData and x.Symbol.SecurityType == SecurityType.Equity and x.DollarVolume > 1e6 and ' ' not in x.Symbol.Value ] # Select top 500 based on dollar volume selected = sorted(filtered, key=lambda x: x.DollarVolume, reverse=True)[:500] self.LogLimited(f"Coarse Selection: {len(selected)} equity symbols selected based on dollar volume.") # Initialize SMA for new symbols for coarse_fundamental in selected: symbol = coarse_fundamental.Symbol if symbol not in self.sma_indicators: try: sma = self.SMA(symbol, 50, Resolution.Daily) self.sma_indicators[symbol] = sma self.RegisterIndicator(symbol, sma, Resolution.Daily) self.LogLimited(f"SMA(50) initialized for {symbol}.") except Exception as e: self.LogLimited(f"Error initializing SMA for {symbol}: {e}") continue return [x.Symbol for x in selected] def OnSecuritiesChanged(self, changes): for security in changes.AddedSecurities: symbol = security.Symbol if symbol not in self.sma_indicators: try: sma = self.SMA(symbol, 50, Resolution.Daily) self.sma_indicators[symbol] = sma self.RegisterIndicator(symbol, sma, Resolution.Daily) self.LogLimited(f"SMA(50) initialized for newly added {symbol}.") except Exception as e: self.LogLimited(f"Error initializing SMA for newly added {symbol}: {e}") for security in changes.RemovedSecurities: symbol = security.Symbol if symbol in self.sma_indicators: self.sma_indicators.pop(symbol) self.LogLimited(f"SMA(50) removed for {symbol}.") def OnData(self, data): if not data.Bars: return # Skip if no data available advancing_stocks = 0 declining_stocks = 0 advancing_volume = 0 declining_volume = 0 total_stocks = len(data.Bars) # Loop through each symbol in the current data for symbol, bar in data.Bars.items(): try: if bar.Close > bar.Open: advancing_stocks += 1 advancing_volume += bar.Volume elif bar.Close < bar.Open: declining_stocks += 1 declining_volume += bar.Volume # If bar.Close == bar.Open, neither advancing nor declining except Exception as e: self.LogLimited(f"Error processing symbol {symbol}: {e}") continue # Skip to the next symbol self.LogLimited(f"Advancing Stocks: {advancing_stocks}, Declining Stocks: {declining_stocks}") self.LogLimited(f"Advancing Volume: {advancing_volume}, Declining Volume: {declining_volume}") # Calculate Indicators ad_ratio = (advancing_stocks / declining_stocks) if declining_stocks > 0 else float('inf') volume_breadth = advancing_volume - declining_volume percent_above_ma = self.CalculatePercentAboveMovingAverage(data, total_stocks) trin = ((advancing_stocks / declining_stocks) / (advancing_volume / declining_volume)) if declining_volume > 0 else 0 self.LogLimited(f"A/D Ratio: {ad_ratio:.2f}, Volume Breadth: {volume_breadth}") self.LogLimited(f"Percent Above MA: {percent_above_ma:.2f}%, TRIN: {trin:.2f}") # Update A/D Line net_advances = advancing_stocks - declining_stocks self.ad_line += net_advances # Sentiment Score self.total_sentiment_score = self.CalculateSentimentScore(ad_ratio, percent_above_ma, trin) # Log the sentiment metrics self.LogLimited(f"Market Sentiment: {self.total_sentiment_score:.2f} | A/D Line: {self.ad_line} | A/D Ratio: {ad_ratio:.2f} | TRIN: {trin:.2f}") # Plotting self.Plot("Sentiment", "Market Sentiment", self.total_sentiment_score) self.Plot("Indicators", "A/D Line", self.ad_line) self.Plot("Indicators", "A/D Ratio", ad_ratio) self.Plot("Indicators", "TRIN", trin) self.Plot("Indicators", "% Above MA", percent_above_ma) self.Plot("Indicators", "Volume Breadth", volume_breadth) def CalculatePercentAboveMovingAverage(self, data, total_stocks): """Calculate the percentage of stocks above their 50-day moving average.""" count_above_ma = 0 for symbol, bar in data.Bars.items(): if symbol in self.sma_indicators: sma = self.sma_indicators[symbol].Current.Value if sma is not None and self.Securities[symbol].Price > sma: count_above_ma += 1 percent_above_ma = (count_above_ma / total_stocks) * 100 if total_stocks > 0 else 0 self.LogLimited(f"Count Above MA: {count_above_ma}, Total Stocks: {total_stocks}, Percent Above MA: {percent_above_ma:.2f}%") return percent_above_ma def CalculateSentimentScore(self, ad_ratio, percent_above_ma, trin): """Combine multiple indicators into a composite sentiment score.""" # Normalize and weight indicators (example weights: 0.4, 0.4, 0.2) normalized_ad_ratio = min(max(ad_ratio / 2, -1), 1) # Normalize between -1 and 1 normalized_percent_above_ma = (percent_above_ma - 50) / 50 # Normalize 50% as neutral normalized_trin = min(max(1 - trin, -1), 1) # Invert TRIN (lower is bullish) sentiment_score = (0.4 * normalized_ad_ratio + 0.4 * normalized_percent_above_ma + 0.2 * normalized_trin) self.LogLimited(f"Normalized A/D Ratio: {normalized_ad_ratio:.2f}, Normalized % Above MA: {normalized_percent_above_ma:.2f}, Normalized TRIN: {normalized_trin:.2f}") self.LogLimited(f"Composite Sentiment Score: {sentiment_score:.2f}") return sentiment_score def LogLimited(self, message): current_date = self.Time.date() if current_date != self.last_log_date: self.current_log_count = 0 self.last_log_date = current_date if self.current_log_count < self.max_logs_per_day: self.Log(message) self.current_log_count += 1