eshan6704 commited on
Commit
aa42e53
Β·
verified Β·
1 Parent(s): 6073f82

Delete app/yahooinfo3.py

Browse files
Files changed (1) hide show
  1. app/yahooinfo3.py +0 -383
app/yahooinfo3.py DELETED
@@ -1,383 +0,0 @@
1
- # ==============================
2
- # Imports
3
- # ==============================
4
- import yfinance as yf
5
- import pandas as pd
6
- import traceback
7
- from datetime import datetime, timezone
8
-
9
- from .persist import exists, load, save
10
-
11
-
12
- # ==============================
13
- # Yahoo Finance fetch
14
- # ==============================
15
- def yfinfo(symbol):
16
- try:
17
- t = yf.Ticker(symbol + ".NS")
18
- info = t.info
19
- return info if isinstance(info, dict) else {}
20
- except Exception as e:
21
- return {"__error__": str(e)}
22
-
23
-
24
- # ==============================
25
- # Icons
26
- # ==============================
27
- MAIN_ICONS = {
28
- "Price / Volume": "πŸ“ˆ",
29
- "Fundamentals": "πŸ“Š",
30
- "Trend": "πŸ“ˆ",
31
- "Signals": "🧠",
32
- "Company Profile": "🏒",
33
- "Management": "πŸ‘”"
34
- }
35
-
36
-
37
- # ==============================
38
- # Layout helpers
39
- # ==============================
40
- def column_layout(html):
41
- return f"""
42
- <style>
43
- .grid {{
44
- display:grid;
45
- gap:10px;
46
- grid-template-columns:repeat(3,1fr);
47
- }}
48
- @media(max-width:1024px) {{
49
- .grid {{ grid-template-columns:repeat(2,1fr); }}
50
- }}
51
- @media(max-width:640px) {{
52
- .grid {{ grid-template-columns:1fr; }}
53
- }}
54
- .pos {{ color:#0a7d32;font-weight:600; }}
55
- .neg {{ color:#b00020;font-weight:600; }}
56
- </style>
57
- <div class="grid">{html}</div>
58
- """
59
-
60
-
61
- def collapsible(title, body):
62
- return f"""
63
- <details open>
64
- <summary style="cursor:pointer;font-weight:600;font-size:15px;padding:6px 0;">
65
- {title}
66
- </summary>
67
- {body}
68
- </details>
69
- """
70
-
71
-
72
- def html_card(title, body, mini=False, shade=0):
73
- font = "12px" if mini else "14px"
74
- pad = "6px" if mini else "10px"
75
- shades = ["#e6f0fa","#d7e3f5","#c8d6f0"]
76
-
77
- return f"""
78
- <div style="background:{shades[shade%3]};
79
- border:1px solid #a3c0e0;
80
- border-radius:8px;
81
- padding:{pad};
82
- font-size:{font};">
83
- <div style="font-weight:600;margin-bottom:6px;">
84
- {title}
85
- </div>
86
- {body}
87
- </div>
88
- """
89
-
90
-
91
- # ==============================
92
- # Formatting helpers
93
- # ==============================
94
- def human_number(n):
95
- try:
96
- n = float(n)
97
- if abs(n) >= 1e7: return f"{n/1e7:.2f}Cr"
98
- if abs(n) >= 1e5: return f"{n/1e5:.2f}L"
99
- if abs(n) >= 1e3: return f"{n/1e3:.2f}K"
100
- return f"{n:,.2f}"
101
- except:
102
- return str(n)
103
-
104
-
105
- # ---------- DATE FIX (ROBUST) ----------
106
- DATE_KEYWORDS = (
107
- "date", "time", "timestamp",
108
- "fiscal", "quarter",
109
- "earnings", "dividend"
110
- )
111
-
112
- def looks_like_unix_ts(v):
113
- try:
114
- v = int(v)
115
- return (
116
- 946684800 <= v <= 4102444800 or # seconds
117
- 946684800000 <= v <= 4102444800000 # milliseconds
118
- )
119
- except:
120
- return False
121
-
122
-
123
- def unix_to_date(v):
124
- try:
125
- v = int(v)
126
- if v > 10**12:
127
- v //= 1000
128
- return datetime.fromtimestamp(v, tz=timezone.utc).strftime("%d %b %Y")
129
- except:
130
- return v
131
-
132
-
133
- def format_value(k, v):
134
- lk = k.lower()
135
-
136
- # --- DATE HANDLING ---
137
- if isinstance(v, (int, float)) and looks_like_unix_ts(v):
138
- if any(x in lk for x in DATE_KEYWORDS):
139
- return unix_to_date(v)
140
-
141
- # --- NUMBERS ---
142
- if isinstance(v, (int, float)):
143
- cls = "pos" if v > 0 else "neg" if v < 0 else ""
144
- if "percent" in lk:
145
- return f'<span class="{cls}">{v:.2f}%</span>'
146
- if any(x in lk for x in [
147
- "marketcap","revenue","income",
148
- "value","cap","enterprise"
149
- ]):
150
- return f'<span class="{cls}">β‚Ή{human_number(v)}</span>'
151
- return f'<span class="{cls}">{human_number(v)}</span>'
152
-
153
- return v
154
-
155
-
156
- def make_table(df):
157
- return "".join(
158
- f"""
159
- <div style="display:flex;justify-content:space-between;
160
- border-bottom:1px dashed #bcd0ea;padding:2px 0;">
161
- <span>{r.Field}</span>
162
- <span>{r.Value}</span>
163
- </div>
164
- """
165
- for r in df.itertuples()
166
- )
167
-
168
-
169
- # ==============================
170
- # Keys
171
- # ==============================
172
- NOISE_KEYS = {
173
- "maxAge","priceHint","triggerable",
174
- "customPriceAlertConfidence",
175
- "sourceInterval","exchangeDataDelayedBy",
176
- "esgPopulated"
177
- }
178
-
179
- SHORT_NAMES = {
180
- "regularMarketPrice":"Price",
181
- "regularMarketChange":"Chg",
182
- "regularMarketChangePercent":"Chg%",
183
- "regularMarketOpen":"Open",
184
- "regularMarketDayHigh":"High",
185
- "regularMarketDayLow":"Low",
186
- "regularMarketVolume":"Vol",
187
- "marketCap":"MCap",
188
- "trailingPE":"PE",
189
- "forwardPE":"FwdPE",
190
- "priceToBook":"PB",
191
- "epsTrailingTwelveMonths":"EPS",
192
- "returnOnEquity":"ROE",
193
- "returnOnAssets":"ROA",
194
- "profitMargins":"Margin",
195
- "debtToEquity":"D/E",
196
- "mostRecentQuarter":"Recent Q",
197
- "lastFiscalYearEnd":"FY End",
198
- "nextFiscalYearEnd":"Next FY"
199
- }
200
-
201
- PIN_PRICE = ["Price","Chg","Chg%","Open","High","Low","Vol"]
202
- PIN_FUND = ["MCap","PE","PB","EPS","ROE","ROA","Margin","D/E"]
203
-
204
- def pretty_key(k):
205
- return SHORT_NAMES.get(k, k[:16])
206
-
207
-
208
- # ==============================
209
- # Classification
210
- # ==============================
211
- def classify(k, v):
212
- lk = k.lower()
213
- if k == "companyOfficers":
214
- return "management"
215
- if any(x in lk for x in [
216
- "pe","pb","roe","roa","margin",
217
- "debt","revenue","profit","eps","cap"
218
- ]):
219
- return "fundamental"
220
- if isinstance(v, (int, float)):
221
- return "price_volume"
222
- if isinstance(v, str) and len(v) > 80:
223
- return "long_text"
224
- return "profile"
225
-
226
-
227
- def group_info(info):
228
- g = {
229
- "price_volume": {},
230
- "fundamental": {},
231
- "profile": {},
232
- "management": {},
233
- "long_text": {}
234
- }
235
- for k,v in info.items():
236
- if k in NOISE_KEYS or v in [None,"",[],{}]:
237
- continue
238
- g[classify(k,v)][k] = v
239
- return g
240
-
241
-
242
- # ==============================
243
- # Builders
244
- # ==============================
245
- def build_df(data, pinned=None):
246
- rows = [(pretty_key(k), format_value(k,v)) for k,v in data.items()]
247
- pinned = pinned or []
248
- rows.sort(key=lambda x: (
249
- 0 if x[0] in pinned else 1,
250
- pinned.index(x[0]) if x[0] in pinned else x[0]
251
- ))
252
- return pd.DataFrame(rows, columns=["Field","Value"])
253
-
254
-
255
- def split_df(df):
256
- n = len(df)
257
- cols = 1 if n <= 6 else 2 if n <= 14 else 3
258
- size = (n + cols - 1) // cols
259
- return [df.iloc[i:i+size] for i in range(0, n, size)]
260
-
261
-
262
- # ==============================
263
- # Trend & Signals
264
- # ==============================
265
- def build_trend(info):
266
- rows = []
267
- p = info.get("regularMarketPrice")
268
- l = info.get("fiftyTwoWeekLow")
269
- h = info.get("fiftyTwoWeekHigh")
270
- d50 = info.get("fiftyDayAverage")
271
- beta = info.get("beta")
272
-
273
- if p and l and h:
274
- rows.append(("52W Position", f"{(p-l)/(h-l)*100:.1f}%"))
275
- if p and d50:
276
- rows.append(("vs 50DMA", "Above ↑" if p>d50 else "Below ↓"))
277
- if beta:
278
- rows.append(("Risk", "High" if beta>1.3 else "Low" if beta<0.8 else "Moderate"))
279
-
280
- return pd.DataFrame(rows, columns=["Field","Value"])
281
-
282
-
283
- def build_signals(info):
284
- rows = []
285
- pe = info.get("trailingPE")
286
- roe = info.get("returnOnEquity")
287
- p = info.get("regularMarketPrice")
288
- d50 = info.get("fiftyDayAverage")
289
-
290
- if pe:
291
- rows.append(("Valuation","Expensive" if pe>35 else "Cheap" if pe<15 else "Fair"))
292
- if p and d50:
293
- rows.append(("Momentum","Strong" if p>d50 else "Weak"))
294
- if roe:
295
- rows.append(("Quality","High" if roe>0.18 else "Average"))
296
-
297
- return pd.DataFrame(rows, columns=["Field","Value"])
298
-
299
-
300
- # ==============================
301
- # MAIN
302
- # ==============================
303
- def fetch_info(symbol):
304
- key = f"info_{symbol}"
305
-
306
- if exists(key,"html"):
307
- cached = load(key,"html")
308
- if cached:
309
- return cached
310
-
311
- try:
312
- info = yfinfo(symbol)
313
- if "__error__" in info:
314
- return "No data"
315
-
316
- g = group_info(info)
317
- html = ""
318
-
319
- if g["price_volume"]:
320
- df = build_df(g["price_volume"], PIN_PRICE)
321
- html += collapsible(
322
- f"{MAIN_ICONS['Price / Volume']} Price / Volume",
323
- column_layout("".join(
324
- html_card("Price", make_table(c), mini=True)
325
- for c in split_df(df)
326
- ))
327
- )
328
-
329
- if g["fundamental"]:
330
- df = build_df(g["fundamental"], PIN_FUND)
331
- html += collapsible(
332
- f"{MAIN_ICONS['Fundamentals']} Fundamentals",
333
- column_layout("".join(
334
- html_card("Fundamentals", make_table(c), mini=True)
335
- for c in split_df(df)
336
- ))
337
- )
338
-
339
- trend = build_trend(info)
340
- if not trend.empty:
341
- html += collapsible(
342
- f"{MAIN_ICONS['Trend']} Trend Summary",
343
- html_card("Trend", make_table(trend), mini=True)
344
- )
345
-
346
- sig = build_signals(info)
347
- if not sig.empty:
348
- html += collapsible(
349
- f"{MAIN_ICONS['Signals']} Smart Signals",
350
- html_card("Signals", make_table(sig), mini=True)
351
- )
352
-
353
- if g["profile"]:
354
- df = build_df(g["profile"])
355
- html += collapsible(
356
- f"{MAIN_ICONS['Company Profile']} Company Profile",
357
- column_layout("".join(
358
- html_card("Profile", make_table(c), mini=True)
359
- for c in split_df(df)
360
- ))
361
- )
362
-
363
- if g["management"].get("companyOfficers"):
364
- cards = ""
365
- for o in g["management"]["companyOfficers"]:
366
- cards += html_card(
367
- o.get("name",""),
368
- o.get("title",""),
369
- mini=True
370
- )
371
- html += collapsible(
372
- f"{MAIN_ICONS['Management']} Management",
373
- column_layout(cards)
374
- )
375
-
376
- for k,v in g["long_text"].items():
377
- html += collapsible(pretty_key(k), v)
378
-
379
- save(key, html, "html")
380
- return html
381
-
382
- except Exception:
383
- return f"<pre>{traceback.format_exc()}</pre>"