-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfunctions.py
More file actions
323 lines (265 loc) · 10.6 KB
/
functions.py
File metadata and controls
323 lines (265 loc) · 10.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
import yfinance as yf
import json
from tickerMap import nse_sector_map,bse_sector_map,us_sector_map,company_ticker_map
import datetime
import re
def get_Full_ticker(ticker):
if ticker.lower() in company_ticker_map:
return company_ticker_map[ticker.lower()]
today_price = yf.Ticker(ticker).history(period="1d")
if today_price.empty:
for suffix in [".NS",".BO"]:
full_ticker = ticker+suffix
data = yf.Ticker(full_ticker).history(period="1d")
if not data.empty:
ticker = full_ticker
break
else:
return ticker
today_price = yf.Ticker(ticker).history(period="1d")
if today_price.empty:
return None
else:
return ticker
def get_stock_price(symbol):
ticker = symbol.upper()
end_date = datetime.date.today()
start_date = end_date-datetime.timedelta(days=30)
ticker = get_Full_ticker(ticker)
today_price = yf.Ticker(ticker).history(period="1d")
data = yf.download(ticker,start=start_date,end=end_date,auto_adjust=True, progress=False)
close_prices=data['Close']
avg = close_prices.mean()
recent =today_price['Close'].iloc[-1]
return f"The 30-day average for {ticker}: {avg[ticker]:.2f}\nLast closed price: {recent:.2f}"
def analyze_financials(symbol):
symbol = symbol.upper()
currency_symbol = "₹" if "." in symbol else "$"
symbol = get_Full_ticker(symbol)
ticker = yf.Ticker(symbol)
info = ticker.info
try:
quarterly_cash_flow = ticker.quarterly_cashflow
if quarterly_cash_flow.empty:
raise ValueError("Empty cash flow data.")
latest_column = quarterly_cash_flow.columns[0]
keys = [
"Free Cash Flow",
"Capital Expenditure",
"Operating Cash Flow",
"Net Income From Continuing Operations"
]
cash_summary = {}
for key in keys:
if key in quarterly_cash_flow.index:
cash_summary[key] = quarterly_cash_flow.loc[key, latest_column]
else:
cash_summary[key] = "N/A"
except Exception as e:
cash_summary = {k: "N/A" for k in [
"Free Cash Flow",
"Capital Expenditure",
"Operating Cash Flow",
"Net Income From Continuing Operations"
]}
# Valuation summary with dynamic currency
valuation_summary = {
"Market Cap": f"{currency_symbol}{info.get('marketCap', 0):,}",
"P/E Ratio": info.get("trailingPE", "N/A"),
"Profit Margins": f"{info.get('profitMargins', 0) * 100:.2f}%" if info.get("profitMargins") else "N/A",
"Gross Margin": f"{info.get('grossMargins', 0) * 100:.2f}%" if info.get("grossMargins") else "N/A",
"Revenue Growth": f"{info.get('revenueGrowth', 0) * 100:.2f}%" if info.get("revenueGrowth") else "N/A",
"Earnings Growth": f"{info.get('earningsGrowth', 0) * 100:.2f}%" if info.get("earningsGrowth") else "N/A",
"Return on Equity (ROE)": f"{info.get('returnOnEquity', 0) * 100:.2f}%" if info.get("returnOnEquity") else "N/A",
"Return on Assets (ROA)": f"{info.get('returnOnAssets', 0) * 100:.2f}%" if info.get("returnOnAssets") else "N/A",
"Debt to Equity": info.get("debtToEquity", "N/A"),
"Dividend Rate": f"{currency_symbol}{info.get('dividendRate', 'N/A')}",
"Dividend Yield": f"{info.get('dividendYield', 0) * 100:.2f}%" if info.get("dividendYield") else "N/A",
"Payout Ratio": info.get("payoutRatio", "N/A"),
"52 Week High": f"{currency_symbol}{info.get('fiftyTwoWeekHigh', 'N/A')}",
"52 Week Low": f"{currency_symbol}{info.get('fiftyTwoWeekLow', 'N/A')}",
"Target Price": f"{currency_symbol}{info.get('targetMeanPrice', 'N/A')} (High: {currency_symbol}{info.get('targetHighPrice', 'N/A')} | Low: {currency_symbol}{info.get('targetLowPrice', 'N/A')})",
}
# Format output
lines = ["📊 **Financial Overview**\n"]
lines.append("**💰 Cash Flow Metrics:**")
for key, val in cash_summary.items():
formatted = f"{currency_symbol}{val:,.0f}" if isinstance(val, (int, float)) else val
lines.append(f"- {key}: {formatted}")
lines.append("\n**📈 Valuation & Ratios:**")
for key, val in valuation_summary.items():
lines.append(f"- {key}: {val}")
return "\n".join(lines)
def parse_financials_string(financials_str: str) -> dict:
summary = {}
# Match lines like "- Key: Value"
lines = financials_str.splitlines()
for line in lines:
match = re.match(r"^- (.*?):\s*(.*)", line.strip())
if match:
key, value = match.groups()
summary[key.strip()] = value.strip()
return summary
def score_based_on_financials(summary):
result = {
"Profitability": 0,
"Cash Flow": 0,
"Growth": 0,
"Valuation": 0,
"Shareholder Returns": 0
}
def get_pct(val):
try: return float(str(val).strip('%'))
except: return 0
def get_num(val):
try: return float(str(val).replace(',', ''))
except: return 0
# ---- Profitability (Max 25) ----
try:
if get_num(summary.get("Net Income From Continuing Operations")) > 0:
result["Profitability"] += 5
except: pass
try:
pm = get_pct(summary.get("Profit Margins", "0"))
result["Profitability"] += max(1, min((pm / 25) * 5, 5))
except: pass
try:
roe = get_pct(summary.get("Return on Equity (ROE)", "0"))
result["Profitability"] += max(1, min((roe / 30) * 5, 5))
except: pass
try:
roa = get_pct(summary.get("Return on Assets (ROA)", "0"))
result["Profitability"] += max(1, min((roa / 15) * 5, 5))
except: pass
try:
gm = get_pct(summary.get("Gross Margin", "0"))
result["Profitability"] += max(1, min((gm / 50) * 5, 5))
except: pass
# ---- Cash Flow (Max 20) ----
try:
fcf = get_num(summary.get("Free Cash Flow"))
result["Cash Flow"] += min((fcf / 2e10) * 6, 6) # scaled to $20B
except: pass
try:
ocf = get_num(summary.get("Operating Cash Flow"))
result["Cash Flow"] += min((ocf / 2e10) * 5, 5)
except:
ocf = 0
try:
capex = get_num(summary.get("Capital Expenditure"))
if ocf > 0:
capex_ratio = abs(capex) / ocf
result["Cash Flow"] += max(1, (1 - capex_ratio) * 4)
except: pass
try:
de = get_num(summary.get("Debt to Equity", 2))
if de == 0:
result["Cash Flow"] += 5
else:
result["Cash Flow"] += max(1, min((1.5 / de) * 5, 5))
except: pass
# ---- Growth (Max 15) ----
try:
rg = get_pct(summary.get("Revenue Growth"))
result["Growth"] += max(1, min((rg / 10) * 7, 7))
except: pass
try:
eg = get_pct(summary.get("Earnings Growth"))
result["Growth"] += max(0, min((eg / 10) * 8, 8)) if eg > 0 else 0
except: pass
# ---- Valuation (Max 15) ----
try:
pe = get_num(summary.get("P/E Ratio"))
if 10 <= pe <= 30:
result["Valuation"] += 10
elif pe < 10:
result["Valuation"] += (pe / 10) * 8 + 2
elif pe < 50:
result["Valuation"] += max(0, ((50 - pe) / 20) * 8)
except: pass
try:
current = get_num(summary.get("Current Price", 0))
target = get_num(summary.get("Target Price", "0").split()[0])
if current and target:
ratio = current / target
if ratio <= 1:
result["Valuation"] += 5
elif ratio <= 1.25:
result["Valuation"] += max(0, (1.25 - ratio) * 20)
except: pass
# ---- Shareholder Returns (Max 20) ----
try:
dy = get_pct(summary.get("Dividend Yield"))
result["Shareholder Returns"] += 1 + min((dy / 4) * 4, 4)
except: pass
try:
pr = get_num(summary.get("Payout Ratio")) * 100
if 20 <= pr <= 60:
result["Shareholder Returns"] += 5
elif 0 < pr < 20:
result["Shareholder Returns"] += (pr / 20) * 3
elif 60 < pr < 80:
result["Shareholder Returns"] += max(0, (80 - pr) / 20 * 3)
except: pass
try:
rating = summary.get("Analyst Rating", "").lower()
if "buy" in rating:
result["Shareholder Returns"] += 5
elif "hold" in rating:
result["Shareholder Returns"] += 2
else:
result["Shareholder Returns"] += 1
except: pass
try:
high = get_num(summary.get("52 Week High"))
low = get_num(summary.get("52 Week Low"))
if high:
spread = (high - low) / high
result["Shareholder Returns"] += max(1, (0.3 - spread) / 0.3 * 5)
except: pass
return {k: round(max(0, min(v, {"Profitability": 25, "Cash Flow": 20, "Growth": 15, "Valuation": 15, "Shareholder Returns": 20}[k])), 0) for k, v in result.items()}
def analyze_sector(identifier,sector):
sector_name = sector
top_comp = []
if(identifier!=""):
identifier=get_Full_ticker(identifier)
# Check if identifier looks like a ticker (e.g., "TCS.NS", "AAPL")
if "." in identifier or identifier.isupper():
# Treat as ticker
ticker_obj = yf.Ticker(identifier)
info = ticker_obj.info
sector_name = info.get("sector", "").lower()
# Determine exchange
if '.' in identifier:
exchange = identifier.split('.')[1].upper()
else:
exchange = 'US'
if exchange == 'NS':
top_comp = nse_sector_map.get(sector_name, [])
elif exchange == 'BO':
top_comp = bse_sector_map.get(sector_name, [])
else:
top_comp = us_sector_map.get(sector_name, [])
else:
sector_name = sector.lower()
top_comp = (
nse_sector_map.get(sector_name)
or bse_sector_map.get(sector_name)
or us_sector_map.get(sector_name)
or []
)
# Analyze each company in the sector
sector_analysis = []
for comp in top_comp:
try:
summary = analyze_financials(comp)
sector_analysis.append(f"📊 **{comp}**\n{summary}\n")
except Exception as e:
sector_analysis.append(f"⚠️ Could not analyze {comp}: {e}")
if not sector_analysis:
return f"❌ No companies found for sector `{sector_name}`."
return f"🏭 **Sector Analysis: {sector_name.title()}**\n\n" + "\n".join(sector_analysis)
# raw_output = analyze_financials("AAPL")
# parsed = parse_financials_string(raw_output)
# scores = score_based_on_financials(parsed)
# print(raw_output,parsed,scores)