Annual EPS
This commit is contained in:
parent
cb098278c9
commit
b6c6518ad4
16
src/main.py
16
src/main.py
@ -1,6 +1,7 @@
|
||||
import datetime
|
||||
from screener.data_fetcher import validate_date_range, fetch_financial_data, get_stocks_in_time_range
|
||||
from screener.c_canslim import check_quarterly_earnings, check_sales_growth, check_return_on_equity
|
||||
from screener.c_canslim import check_quarterly_earnings
|
||||
from screener.a_canslim import check_annual_eps_growth # New module
|
||||
from screener.csv_appender import append_scores_to_csv
|
||||
|
||||
def main():
|
||||
@ -27,21 +28,18 @@ def main():
|
||||
if not data:
|
||||
print(f"Warning: No data returned for {symbol}. Assigning default score.")
|
||||
scores = {
|
||||
"EPS_Score": 0.25, # EPS Growth
|
||||
"Sales_Score": 0.25, # Sales Growth
|
||||
"ROE_Score": 0.25 # Return on Equity
|
||||
"EPS_Score": 0.25, # Quarterly EPS Growth
|
||||
"Annual_EPS_Score": 0.25 # Annual EPS Growth
|
||||
}
|
||||
else:
|
||||
# Extract relevant fields
|
||||
quarterly_eps = data.get("eps", [])
|
||||
sales_growth = data.get("sales_growth", [])
|
||||
roe = 18 # Placeholder, modify if needed
|
||||
quarterly_eps = data.get("quarterly_eps", [])
|
||||
annual_eps = data.get("annual_eps", [])
|
||||
|
||||
# 5️⃣ Compute CANSLIM Scores
|
||||
scores = {
|
||||
"EPS_Score": check_quarterly_earnings(quarterly_eps),
|
||||
"Sales_Score": check_sales_growth(sales_growth),
|
||||
"ROE_Score": check_return_on_equity(roe)
|
||||
"Annual_EPS_Score": check_annual_eps_growth(annual_eps)
|
||||
}
|
||||
|
||||
# 6️⃣ Append results to a **generic** CSV file in `data/metrics/`
|
||||
|
||||
29
src/screener/a_canslim.py
Normal file
29
src/screener/a_canslim.py
Normal file
@ -0,0 +1,29 @@
|
||||
def check_annual_eps_growth(annual_eps):
|
||||
"""
|
||||
Checks for 25%-50%+ annual EPS growth over the last three years.
|
||||
|
||||
Args:
|
||||
annual_eps (list): List of annual EPS values (must contain at least 3 years of data).
|
||||
|
||||
Returns:
|
||||
float: Score (1 pass, 0 fail, 0.25 insufficient data).
|
||||
"""
|
||||
if not annual_eps or len(annual_eps) < 3:
|
||||
return 0.25 # Not enough data for 3-year growth calculation
|
||||
|
||||
# Calculate year-over-year EPS growth rates
|
||||
growth_rates = []
|
||||
for i in range(1, len(annual_eps)): # Compare consecutive years
|
||||
prev_eps = annual_eps[i - 1]
|
||||
current_eps = annual_eps[i]
|
||||
|
||||
if prev_eps <= 0: # Avoid division by zero or negative EPS
|
||||
return 0.25
|
||||
|
||||
growth = ((current_eps - prev_eps) / abs(prev_eps)) * 100
|
||||
growth_rates.append(growth)
|
||||
|
||||
# Check if all growth rates are 25%+
|
||||
if all(rate >= 25 for rate in growth_rates):
|
||||
return 1 # Pass
|
||||
return 0 # Fail
|
||||
@ -31,8 +31,9 @@ def validate_date_range(start_date, end_date, required_quarters=4):
|
||||
|
||||
def fetch_financial_data(symbol, start_date, end_date):
|
||||
"""
|
||||
Fetch financial data (EPS, Sales Growth) from stock_financials table
|
||||
for a given stock symbol within a specific date range.
|
||||
Fetch financial data for a given stock symbol, including:
|
||||
- Quarterly EPS for EPS Score
|
||||
- Annual EPS for Annual EPS Score
|
||||
|
||||
Args:
|
||||
symbol (str): Stock ticker symbol.
|
||||
@ -40,21 +41,20 @@ def fetch_financial_data(symbol, start_date, end_date):
|
||||
end_date (str or datetime): End date for data retrieval.
|
||||
|
||||
Returns:
|
||||
dict: A dictionary containing calculated EPS and sales growth.
|
||||
dict: Contains EPS, sales growth, and annual EPS.
|
||||
"""
|
||||
client = create_client()
|
||||
|
||||
# Query stock_financials for revenue, net income, and EPS
|
||||
query = f"""
|
||||
SELECT
|
||||
filing_date,
|
||||
diluted_eps,
|
||||
revenue,
|
||||
net_income,
|
||||
diluted_eps -- Using diluted EPS for accuracy
|
||||
timeframe
|
||||
FROM stock_db.stock_financials
|
||||
WHERE ticker = '{symbol}'
|
||||
AND filing_date BETWEEN toDate('{start_date}') AND toDate('{end_date}')
|
||||
AND timeframe = 'quarterly' -- Ensure only quarterly reports are used
|
||||
AND (timeframe = 'quarterly' OR timeframe = 'annual') -- Fetch both annual and quarterly data
|
||||
ORDER BY filing_date ASC
|
||||
"""
|
||||
|
||||
@ -63,36 +63,36 @@ def fetch_financial_data(symbol, start_date, end_date):
|
||||
if not result.result_rows:
|
||||
return {}
|
||||
|
||||
# Extracting data
|
||||
dates = []
|
||||
quarterly_eps = []
|
||||
annual_eps = []
|
||||
revenues = []
|
||||
net_incomes = []
|
||||
eps_values = []
|
||||
sales_growth = []
|
||||
|
||||
for row in result.result_rows:
|
||||
dates.append(row[0])
|
||||
revenues.append(row[1])
|
||||
net_incomes.append(row[2])
|
||||
eps_values.append(row[3]) # Directly using diluted EPS
|
||||
filing_date, eps, revenue, timeframe = row
|
||||
|
||||
if timeframe == "quarterly":
|
||||
quarterly_eps.append(eps)
|
||||
revenues.append(revenue)
|
||||
elif timeframe == "annual":
|
||||
annual_eps.append(eps)
|
||||
|
||||
# Calculate Sales Growth (Quarter-over-Quarter)
|
||||
for i in range(1, len(revenues)): # Start from index 1 since we compare with previous
|
||||
prev_revenue = revenues[i - 1]
|
||||
current_revenue = revenues[i]
|
||||
if prev_revenue > 0: # Avoid division by zero
|
||||
if prev_revenue > 0:
|
||||
growth = ((current_revenue - prev_revenue) / prev_revenue) * 100
|
||||
else:
|
||||
growth = None # Not enough data
|
||||
sales_growth.append(growth)
|
||||
|
||||
# Pad sales_growth list to match length of EPS (since first quarter lacks a previous value)
|
||||
sales_growth.insert(0, None) # First quarter doesn't have a previous comparison
|
||||
sales_growth.insert(0, None) # First quarter lacks comparison
|
||||
|
||||
return {
|
||||
"symbol": symbol,
|
||||
"dates": dates,
|
||||
"eps": eps_values,
|
||||
"quarterly_eps": quarterly_eps, # Used for EPS_Score
|
||||
"annual_eps": annual_eps, # Used for Annual_EPS_Score
|
||||
"sales_growth": sales_growth
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user