feat: Add institutional sponsorship check for CANSLIM strategy

This commit is contained in:
Bobby Abellana (aider) 2025-02-06 18:56:38 -08:00
parent 9b6871d575
commit f62cd47292
No known key found for this signature in database
GPG Key ID: 647714CC45F3647B

88
src/screener/i_canslim.py Normal file
View File

@ -0,0 +1,88 @@
from db.db_connection import create_client
def check_institutional_sponsorship(symbol):
"""
Determines if a stock has strong institutional sponsorship.
Criteria:
- Should have at least several institutional sponsors
- Look for increasing institutional ownership
- Focus on higher-quality institutions
- Avoid stocks with too much institutional ownership (>80-90%)
Args:
symbol (str): Stock ticker symbol.
Returns:
float: 1 (Pass), 0 (Fail), 0.25 (Insufficient Data)
"""
client = create_client()
# Get current institutional ownership data
query = """
SELECT
COUNT(DISTINCT holder_name) as num_institutions,
SUM(percentage_held) as total_ownership,
MAX(date_reported) as latest_date
FROM stock_db.yf_institutional_holders
WHERE ticker = '{}'
GROUP BY ticker
""".format(symbol)
result = client.query(query)
if not result.result_rows:
return 0.25 # Insufficient data
num_institutions, total_ownership, _ = result.result_rows[0]
# Get ownership trend (comparing with 3 months ago)
trend_query = """
WITH current AS (
SELECT SUM(percentage_held) as current_ownership,
MAX(date_reported) as latest_date
FROM stock_db.yf_institutional_holders
WHERE ticker = '{}'
),
previous AS (
SELECT SUM(percentage_held) as previous_ownership
FROM stock_db.yf_institutional_holders
WHERE ticker = '{}'
AND date_reported <= (SELECT latest_date - INTERVAL 3 MONTH FROM current)
)
SELECT current_ownership, previous_ownership
FROM current, previous
""".format(symbol, symbol)
trend_result = client.query(trend_query)
# Evaluate criteria
if num_institutions is None or total_ownership is None:
return 0.25
# Convert total_ownership to percentage (0-100 scale)
total_ownership = float(total_ownership)
# Criteria thresholds
MIN_INSTITUTIONS = 10
MIN_OWNERSHIP = 20 # percentage
MAX_OWNERSHIP = 85 # percentage
# Basic institutional presence check
has_sufficient_institutions = num_institutions >= MIN_INSTITUTIONS
has_healthy_ownership = MIN_OWNERSHIP <= total_ownership <= MAX_OWNERSHIP
# Check ownership trend
ownership_increasing = False
if trend_result.result_rows:
current_ownership, previous_ownership = trend_result.result_rows[0]
if current_ownership and previous_ownership:
ownership_increasing = current_ownership > previous_ownership
# Final evaluation
if has_sufficient_institutions and has_healthy_ownership and ownership_increasing:
return 1
elif not has_sufficient_institutions or total_ownership < MIN_OWNERSHIP:
return 0
else:
return 0.25 # Borderline cases