pytrade-backend / fundamental.py
Oviya
Track binaries via Git LFS (analysedata.xlsx, TA_Lib wheel)
66dc1bf
from flask import Flask, jsonify
import pandas as pd
import yfinance as yf
import numpy as np
def get_fundamental_details(ticker):
# Fetch the stock data using yfinance
stock = yf.Ticker(ticker)
# Fetch fundamental data and financial statements
fundamental_data = stock.info
income_statement = stock.financials
balance_sheet = stock.balance_sheet
cash_flow_statement = stock.cashflow
current_net_income = income_statement.loc['Net Income'].iloc[0]
previous_net_income = income_statement.loc['Net Income'].iloc[1]
earnings_growth_yoy = 'N/A'
# Calculate Earnings Growth (YoY)
if current_net_income is not None and previous_net_income is not None:
earnings_growth_yoy = ((current_net_income - previous_net_income) / previous_net_income) * 100
current_assets = balance_sheet.loc['Current Assets'].iloc[0] if 'Current Assets' in balance_sheet.index else None
current_liabilities = balance_sheet.loc['Current Liabilities'].iloc[0] if 'Current Liabilities' in balance_sheet.index else None
current_ratio = 'N/A'
# Calculate Earnings Growth (YoY)
if current_assets is not None and current_liabilities is not None:
current_ratio = current_assets/current_liabilities
# Ensure data is transposed for proper indexing
balance_sheet = balance_sheet.T
# Get the latest non-null Debt-to-Equity Ratio
debt_to_equity = "N/A"
total_liabilities_series = total_equity_series = None
if "Total Liabilities Net Minority Interest" in balance_sheet.columns and "Ordinary Shares Number" in balance_sheet.columns:
total_liabilities_series = balance_sheet["Total Liabilities Net Minority Interest"].dropna()
total_equity_series = balance_sheet["Ordinary Shares Number"].dropna()
if not total_liabilities_series.empty and not total_equity_series.empty:
total_liabilities = total_liabilities_series.iloc[0] # Get the latest non-null value
total_equity = total_equity_series.iloc[0] # Get the latest non-null value
if total_liabilities is not None and total_equity is not None and total_equity != 0:
debt_to_equity = total_liabilities / total_equity
fundamental_metrics = {
'EPS': fundamental_data.get('epsTrailingTwelveMonths', None),
'P/E Ratio': fundamental_data.get('trailingPE', None),
'Revenue Growth': fundamental_data.get('revenueGrowth', None),
'Debt-to-Equity Ratio': debt_to_equity,
'Earnings Growth(YoY)': earnings_growth_yoy
}
eps = fundamental_metrics['EPS']
pe_ratio = fundamental_metrics['P/E Ratio']
revenue_growth = fundamental_metrics['Revenue Growth']
debt_to_equity = fundamental_metrics['Debt-to-Equity Ratio']
earnings_growth_yoy = fundamental_metrics['Earnings Growth(YoY)']
# Initialize status variables
earnings_growth_status = "none"
debt_to_equity_status = "none"
pe_ratio_status = "none"
revenue_growth_status = "none"
eps_status = "none"
# Updated Thresholds
earnings_growth_threshold = 0.12 # Earnings Growth > 12% (good)
debt_to_equity_threshold = 1.5 # D/E < 1.5 (good)
pe_ratio_threshold = 25 # P/E < 25 (good)
revenue_growth_threshold = 0.12 # Revenue Growth > 12% (good)
eps_threshold = 0 # EPS > 0 (good)
# Updated Weightages
earnings_growth_weight = 2 # 3.5% weight for earnings growth
debt_to_equity_weight = 1.5 # 2.75% weight for debt-to-equity ratio
pe_ratio_weight = 1.5 # 2.5% weight for P/E ratio
revenue_growth_weight = 2 # 3.5% weight for revenue growth
eps_weight = 3 # 3.75% weight for EPS
# Check and assign status for EPS, if available
if eps is not None:
if eps > eps_threshold:
eps_status = "good"
else:
eps_status = "bad"
# Check and assign status for earnings growth, if available
if earnings_growth_yoy is not None:
if earnings_growth_yoy >= earnings_growth_threshold:
earnings_growth_status = "good"
else:
earnings_growth_status = "bad"
# Check and assign status for debt-to-equity, if available
if debt_to_equity is not None:
if debt_to_equity <= debt_to_equity_threshold:
debt_to_equity_status = "good"
else:
debt_to_equity_status = "bad"
# Check and assign status for P/E ratio, if available
if pe_ratio is not None:
if pe_ratio <= pe_ratio_threshold:
pe_ratio_status = "good"
else:
pe_ratio_status = "bad"
# Check and assign status for revenue growth, if available
if revenue_growth is not None:
if revenue_growth >= revenue_growth_threshold:
revenue_growth_status = "good"
else:
revenue_growth_status = "bad"
# Calculate overall score
overall_fa_score = 0
overall_fa_score += eps_weight if eps_status == "good" else 0
overall_fa_score += earnings_growth_weight if earnings_growth_status == "good" else 0
overall_fa_score += debt_to_equity_weight if debt_to_equity_status == "good" else 0
overall_fa_score += pe_ratio_weight if pe_ratio_status == "good" else 0
overall_fa_score += revenue_growth_weight if revenue_growth_status == "good" else 0
earnings_growth = stock.info.get('earningsGrowth', None)
peg_ratio = None
if pe_ratio is not None and earnings_growth is not None and earnings_growth != 0:
peg_ratio = pe_ratio / earnings_growth
# Financial Metrics (Valuation, Profitability, etc.)
financialMetrics = {
'Market Cap': fundamental_data.get('marketCap', None),
'Price-to-Book (P/B) Ratio': fundamental_data.get('priceToBook', None),
'Price-to-Sales (P/S) Ratio': fundamental_data.get('priceToSalesTrailing12Months', None),
'PEG Ratio': peg_ratio,
'EV/EBITDA': fundamental_data.get('enterpriseToEbitda', None)
}
# Balance Sheet Data
balanceSheetInformation = {
'Total Assets': balance_sheet.loc['Total Assets'].iloc[0] if 'Total Assets' in balance_sheet.index else None,
'Total Liabilities': balance_sheet.loc['Total Liabilities Net Minority Interest'].iloc[0] if 'Total Liabilities Net Minority Interest' in balance_sheet.index else None,
'Total Stockholder Equity': (balance_sheet.loc['Total Assets'].iloc[0] - balance_sheet.loc['Total Liabilities Net Minority Interest'].iloc[0])
if 'Total Assets' in balance_sheet.index and 'Total Liabilities Net Minority Interest' in balance_sheet.index else None,
'Long Term Debt': balance_sheet.loc['Long Term Debt'].iloc[0] if 'Long Term Debt' in balance_sheet.index else None,
'Current Assets': balance_sheet.loc['Current Assets'].iloc[0] if 'Current Assets' in balance_sheet.index else None,
'Current Liabilities': balance_sheet.loc['Current Liabilities'].iloc[0] if 'Current Liabilities' in balance_sheet.index else None,
'Inventory': balance_sheet.loc['Inventory'].iloc[0] if 'Inventory' in balance_sheet.index else None
}
# Income Statement Data
incomeStatement = {
'Total Revenue': income_statement.loc['Total Revenue'].iloc[0] if 'Total Revenue' in income_statement.index else None,
'Operating Income': income_statement.loc['Operating Income'].iloc[0] if 'Operating Income' in income_statement.index else None,
'Net Income': income_statement.loc['Net Income'].iloc[0] if 'Net Income' in income_statement.index else None,
'Gross Profit': income_statement.loc['Gross Profit'].iloc[0] if 'Gross Profit' in income_statement.index else None
}
# Growth Indicators
growthIndicators = {
'Revenue Growth (YoY)': income_statement.loc['Revenue Growth'].iloc[0] if 'Revenue Growth' in income_statement.index else None,
'Profit Margins': (incomeStatement['Net Income'] / incomeStatement['Total Revenue']) * 100 if incomeStatement['Total Revenue'] else None,
'ROE (Return on Equity)': balanceSheetInformation.get('Return on Equity (ROE)', None),
'ROA (Return on Assets)': balanceSheetInformation.get('Return on Assets (ROA)', None)
}
# Assuming your original cashFlowStatement dict is defined here
cashFlowStatement = {
'Operating Cash Flow': cash_flow_statement.loc['Operating Cash Flow'].iloc[0] if 'Operating Cash Flow' in cash_flow_statement.index else None,
'Investing Cash Flow': cash_flow_statement.loc['Investing Cash Flow'].iloc[0] if 'Investing Cash Flow' in cash_flow_statement.index else None,
'Financing Cash Flow': cash_flow_statement.loc['Financing Cash Flow'].iloc[0] if 'Financing Cash Flow' in cash_flow_statement.index else None,
'Cash Flow to Debt Ratio': (
cash_flow_statement.loc['Operating Cash Flow'].iloc[0] / balance_sheet.loc['Long Term Debt'].iloc[0]
if 'Operating Cash Flow' in cash_flow_statement.index and 'Long Term Debt' in balance_sheet.index
else None
)
}
# Replace NaN or None values with 'N/A'
cashFlowStatement = {k: ('N/A' if pd.isna(v) else v) for k, v in cashFlowStatement.items()}
# Company Overview Data
companyOverview = {
'Company Name': fundamental_data.get('longName', None),
'Sector': fundamental_data.get('sector', None),
'Industry': fundamental_data.get('industry', None)
}
# Risk Indicators
riskIndicators = {
'Debt-to-Equity Ratio(Risk)': balanceSheetInformation.get('Long Term Debt', None) / balanceSheetInformation.get('Total Stockholder Equity', None)
if balanceSheetInformation.get('Long Term Debt') and balanceSheetInformation.get('Total Stockholder Equity') else None,
'Interest Coverage Ratio': income_statement.loc['Interest Coverage'].iloc[0] if 'Interest Coverage' in income_statement.index else None,
'Beta (Stock Volatility)': fundamental_data.get('beta', None),
'Quick Ratio': (balanceSheetInformation.get('Current Assets', None) - balanceSheetInformation.get('Inventory', None)) / balanceSheetInformation.get('Current Liabilities', None)
if balanceSheetInformation.get('Current Assets') and balanceSheetInformation.get('Inventory') and balanceSheetInformation.get('Current Liabilities') else None
}
# Dividends
dividends = {
'Payout Ratio': fundamental_data.get('payoutRatio', None),
'Dividend Growth Rate': fundamental_data.get('dividendGrowthRate', None)
}
# Profitability Indicators
profitabilityIndicators = {
'Gross Margin': (income_statement.loc['Gross Profit'].iloc[0] / income_statement.loc['Total Revenue'].iloc[0]) * 100
if 'Gross Profit' in income_statement.index and 'Total Revenue' in income_statement.index else None,
'Operating Margin': (income_statement.loc['Operating Income'].iloc[0] / income_statement.loc['Total Revenue'].iloc[0]) * 100
if 'Operating Income' in income_statement.index and 'Total Revenue' in income_statement.index else None,
'Net Margin': (income_statement.loc['Net Income'].iloc[0] / income_statement.loc['Total Revenue'].iloc[0]) * 100
if 'Net Income' in income_statement.index and 'Total Revenue' in income_statement.index else None
}
# Liquidity Indicators
liquidityIndicators = {
'Cash Ratio': balance_sheet.loc['Cash And Cash Equivalents'].iloc[0] / balance_sheet.loc['Current Liabilities'].iloc[0]
if 'Cash And Cash Equivalents' in balance_sheet.index and 'Current Liabilities' in balance_sheet.index else None,
'Working Capital': balance_sheet.loc['Current Assets'].iloc[0] - balance_sheet.loc['Current Liabilities'].iloc[0]
if 'Current Assets' in balance_sheet.index and 'Current Liabilities' in balance_sheet.index else None
}
investorInsightMetrics = {
'EPS': eps,
'P/E Ratio': pe_ratio,
'Revenue Growth': revenue_growth,
'Debt-to-Equity Ratio': debt_to_equity,
'Earnings Growth(YoY)': earnings_growth_yoy
}
result = {
'EPS': eps_status,
'P/E Ratio': pe_ratio_status,
'Revenue Growth': revenue_growth_status,
'Debt-to-Equity Ratio': debt_to_equity_status,
'Earnings Growth(YoY)': earnings_growth_status
}
def replace_nan_with_na(data):
if isinstance(data, dict):
return {k: replace_nan_with_na(v) for k, v in data.items()}
elif isinstance(data, list):
return [replace_nan_with_na(v) for v in data]
elif pd.isna(data):
return 'N/A'
else:
return data
return replace_nan_with_na({
"fa_strategy": result,
"overall_fa_score": round(overall_fa_score, 2),
"Investor Insight Metrics": investorInsightMetrics,
"Company Overview": companyOverview,
"Growth Indicators": growthIndicators,
"Risk Indicators": riskIndicators,
"Dividends": dividends,
"Cash Flow Statement": cashFlowStatement,
"Financial Metrics": financialMetrics,
"Income Statement": incomeStatement,
"BalanceSheet Information": balanceSheetInformation,
"Profitability Indicators": profitabilityIndicators,
"Liquidity Indicators": liquidityIndicators,
})