115 lines
3.7 KiB
Python
115 lines
3.7 KiB
Python
import csv
|
|
import os
|
|
from db.db_connection import create_client
|
|
|
|
# Load SIC Industry Data
|
|
SIC_LOOKUP = {}
|
|
|
|
def load_sic_data():
|
|
"""Loads SIC Code data into a dictionary from the new CSV location above `src/`."""
|
|
global SIC_LOOKUP
|
|
script_dir = os.path.dirname(os.path.abspath(__file__)) # Get the directory of l_canslim.py
|
|
project_root = os.path.abspath(os.path.join(script_dir, "../../")) # Go up to project root
|
|
sic_file = os.path.join(project_root, "industry_sic_codes.csv") # Adjust path
|
|
|
|
if not os.path.exists(sic_file):
|
|
raise FileNotFoundError(f"Error: SIC Code CSV file not found at {sic_file}")
|
|
|
|
with open(sic_file, mode="r", encoding="utf-8") as file:
|
|
reader = csv.DictReader(file)
|
|
for row in reader:
|
|
sic_code = row["SIC Code"].strip() # Match CSV header exactly
|
|
industry = row["Industry Title"].strip() # Match CSV header exactly
|
|
SIC_LOOKUP[sic_code] = industry
|
|
|
|
# Ensure SIC data is loaded at module import
|
|
load_sic_data()
|
|
|
|
def check_industry_leadership(symbol):
|
|
"""
|
|
Determines if a stock is a leader in its industry group.
|
|
|
|
Criteria:
|
|
- RSI should be 60 or higher as a strength indicator
|
|
- Stock should be trading near its 52-week high
|
|
- Must have valid industry classification
|
|
|
|
Args:
|
|
symbol (str): Stock ticker symbol.
|
|
|
|
Returns:
|
|
float: 1 (Pass), 0 (Fail), 0.25 (Insufficient Data).
|
|
"""
|
|
client = create_client()
|
|
|
|
# First get the SIC code from stock_tickers table
|
|
sic_query = f"""
|
|
SELECT sic_code
|
|
FROM stock_db.stock_tickers
|
|
WHERE ticker = '{symbol}'
|
|
"""
|
|
|
|
# Get RSI from stock_indicators and price data from stock_prices_daily
|
|
metrics_query = f"""
|
|
WITH latest_date AS (
|
|
SELECT MAX(date) as max_date
|
|
FROM stock_db.stock_prices_daily
|
|
WHERE ticker = '{symbol}'
|
|
),
|
|
year_range AS (
|
|
SELECT
|
|
close as current_price,
|
|
(
|
|
SELECT MAX(close)
|
|
FROM stock_db.stock_prices_daily
|
|
WHERE ticker = '{symbol}'
|
|
AND date >= DATE_SUB(
|
|
(SELECT max_date FROM latest_date),
|
|
INTERVAL 52 WEEK
|
|
)
|
|
) as high_52_week
|
|
FROM stock_db.stock_prices_daily
|
|
WHERE ticker = '{symbol}'
|
|
AND date = (SELECT max_date FROM latest_date)
|
|
),
|
|
latest_rsi AS (
|
|
SELECT rsi
|
|
FROM stock_db.stock_indicators
|
|
WHERE ticker = '{symbol}'
|
|
ORDER BY date DESC
|
|
LIMIT 1
|
|
)
|
|
SELECT
|
|
yr.current_price,
|
|
yr.high_52_week,
|
|
lr.rsi
|
|
FROM year_range yr
|
|
CROSS JOIN latest_rsi lr
|
|
"""
|
|
|
|
# Execute queries
|
|
sic_result = client.query(sic_query)
|
|
metrics_result = client.query(metrics_query)
|
|
|
|
if not sic_result.result_rows or not metrics_result.result_rows:
|
|
return 0.25 # Not enough data
|
|
|
|
sic = sic_result.result_rows[0][0]
|
|
if not sic or str(sic) not in SIC_LOOKUP:
|
|
return 0.25 # No SIC industry data available
|
|
|
|
current_price, high_52_week, rsi = metrics_result.result_rows[0]
|
|
|
|
# Ensure we have valid data
|
|
if high_52_week is None or current_price is None or rsi is None:
|
|
return 0.25 # Missing necessary data
|
|
|
|
# Industry Leader Criteria
|
|
passes_rs = rsi >= 60 # Using RSI as a substitute for relative strength
|
|
near_high = current_price >= (high_52_week * 0.90) # Within 10% of 52-week high
|
|
|
|
if passes_rs and near_high:
|
|
return 1 # Stock is an industry leader
|
|
else:
|
|
return 0 # Stock is lagging
|