| Overall Statistics |
|
Total Orders 2723 Average Win -35.75% Average Loss 7.39% Compounding Annual Return -7.907% Drawdown 85.400% Expectancy -1.975 Start Equity 100000 End Equity 73371.46 Net Profit -26.629% Sharpe Ratio 0.211 Sortino Ratio 0.277 Probabilistic Sharpe Ratio 3.739% Loss Rate 75% Win Rate 25% Profit-Loss Ratio -4.84 Alpha -0.02 Beta 2.05 Annual Standard Deviation 0.649 Annual Variance 0.421 Information Ratio 0.1 Tracking Error 0.602 Treynor Ratio 0.067 Total Fees $2206.45 Estimated Strategy Capacity $23000.00 Lowest Capacity Asset AREB XVTYLRAYE2XX Portfolio Turnover 1.15% |
# region imports
from AlgorithmImports import *
# endregion
from datetime import datetime, timedelta
import numpy as np
class StockScreener(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2020, 11, 17)
self.SetCash(100000)
self.UniverseSettings.Resolution = Resolution.Daily
self.UniverseSettings.Asynchronous = True
# Add specific stocks from Finviz results to test data availability
self.symbols = [
"DDD", # 3D Systems Corp
"GILT", # Gilat Satellite Networks
"HRYU", # Hanryu Holdings Inc
"RRGB", # Red Robin Gourmet Burgers
"SPCE", # Virgin Galactic Holdings
"UNCY", # Unicycive Therapeutics
"VSTE", # Vast Renewables
"WDH" # Waterdrop Inc ADR
]
# Test data availability for specific symbols
for symbol in self.symbols:
try:
equity = self.AddEquity(symbol, Resolution.Daily)
history = self.History(equity.Symbol, 200, Resolution.Daily)
# Convert to pandas DataFrame first
history_df = history.loc[str(equity.Symbol)] if len(history) > 0 else None
if history_df is not None and len(history_df) > 0:
self.Debug(f"Data available for {symbol}: {len(history_df)} days of history")
else:
self.Debug(f"No historical data available for {symbol}")
except Exception as e:
self.Debug(f"Error adding {symbol}: {str(e)}")
# Add universe selection
self.AddUniverseSelection(FundamentalUniverseSelectionModel(self.FilterStocks))
self.holdings = {}
def FilterStocks(self, fundamental: List[Fundamental]) -> List[Symbol]:
filtered_stocks = []
for stock in fundamental:
try:
# Log initial check
self.Debug(f"\nAnalyzing {stock.symbol}:")
self.Debug(f"Price: ${stock.price:.2f}, Volume: {stock.volume}")
# Basic filters with logging
if not stock.has_fundamental_data:
self.Debug(f"{stock.symbol}: No fundamental data")
continue
if stock.price >= 7:
self.Debug(f"{stock.symbol}: Price ${stock.price:.2f} >= $7")
continue
if stock.volume <= 50000:
self.Debug(f"{stock.symbol}: Volume {stock.volume} <= 50K")
continue
history = self.History(stock.symbol, 200, Resolution.Daily)
history_df = history.loc[str(stock.symbol)] if len(history) > 0 else None
if history_df is None or len(history_df) < 200:
self.Debug(f"{stock.symbol}: Insufficient history data")
continue
closes = history_df['close']
current_price = closes.iloc[-1]
# Calculate and log technical indicators
sma20 = closes[-20:].mean()
sma50 = closes[-50:].mean()
sma200 = closes[-200:].mean()
self.Debug(f"{stock.symbol} Technical Analysis:" +
f"\n Current Price: ${current_price:.2f}" +
f"\n SMA20: ${sma20:.2f}" +
f"\n SMA50: ${sma50:.2f}" +
f"\n SMA200: ${sma200:.2f}")
# Check each condition individually
conditions = {
"Price < SMA20": current_price < sma20,
"Price > SMA50": current_price > sma50,
"Price > SMA200": current_price > sma200,
"Price Up": closes.iloc[-1] > closes.iloc[-2]
}
# Log which conditions passed/failed
for condition_name, condition_met in conditions.items():
self.Debug(f"{stock.symbol} - {condition_name}: {'✓' if condition_met else '✗'}")
if all(conditions.values()):
filtered_stocks.append(stock.symbol)
shares = int(self.Portfolio.TotalPortfolioValue * 0.1 / current_price)
if shares > 0:
self.MarketOrder(stock.symbol, shares)
self.Debug(f"✓ ORDER PLACED: {shares} shares of {stock.symbol} at ${current_price:.2f}")
except Exception as e:
self.Debug(f"Error processing {stock.symbol}: {str(e)}")
return filtered_stocks
def OnData(self, data):
pass