eshan6704 commited on
Commit
618c884
·
verified ·
1 Parent(s): 24d04ba

Create yahooinfo.py

Browse files
Files changed (1) hide show
  1. yahooinfo.py +312 -0
yahooinfo.py ADDED
@@ -0,0 +1,312 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # ==============================
2
+ # Imports
3
+ # ==============================
4
+ import yfinance as yf
5
+ import pandas as pd
6
+ import traceback
7
+
8
+ # ==============================
9
+ # Yahoo Finance info fetch
10
+ # ==============================
11
+ def yfinfo(symbol):
12
+ try:
13
+ t = yf.Ticker(symbol + ".NS")
14
+ info = t.info
15
+ if not info or not isinstance(info, dict):
16
+ return {}
17
+ return info
18
+ except Exception as e:
19
+ return {"__error__": str(e)}
20
+
21
+ # ==============================
22
+ # Icons
23
+ # ==============================
24
+ SUBGROUP_ICONS = {
25
+ "Live Price": "💹",
26
+ "Volume": "📊",
27
+ "Moving Avg": "📈",
28
+ "Range / Vol": "📉",
29
+ "Bid / Analyst": "📝",
30
+ "Other": "ℹ️"
31
+ }
32
+
33
+ MAIN_ICONS = {
34
+ "Price / Volume": "📈",
35
+ "Fundamentals": "📊",
36
+ "Company Profile": "🏢"
37
+ }
38
+
39
+ # ==============================
40
+ # Column layout wrapper
41
+ # ==============================
42
+ def column_layout(html, min_width=260):
43
+ return f"""
44
+ <div style="
45
+ display:grid;
46
+ grid-template-columns:repeat(auto-fit,minmax({min_width}px,1fr));
47
+ gap:8px;
48
+ align-items:start;
49
+ ">
50
+ {html}
51
+ </div>
52
+ """
53
+
54
+ # ==============================
55
+ # Card renderer
56
+ # ==============================
57
+ def html_card(title, body, mini=False, shade=0):
58
+ font = "12px" if mini else "14px"
59
+ pad = "6px" if mini else "10px"
60
+
61
+ shades = ["#e6f0fa", "#d7e3f5", "#c8d6f0"]
62
+ grads = [
63
+ "linear-gradient(to right,#1a4f8a,#4a7ac7)",
64
+ "linear-gradient(to right,#1f5595,#5584d6)",
65
+ "linear-gradient(to right,#205ca0,#6192e0)"
66
+ ]
67
+
68
+ return f"""
69
+ <div style="
70
+ background:{shades[shade%3]};
71
+ border:1px solid #a3c0e0;
72
+ border-radius:8px;
73
+ padding:{pad};
74
+ font-size:{font};
75
+ box-shadow:0 2px 6px rgba(0,0,0,.08);
76
+ ">
77
+ <div style="
78
+ background:{grads[shade%3]};
79
+ color:white;
80
+ padding:4px 8px;
81
+ border-radius:6px;
82
+ font-weight:600;
83
+ margin-bottom:6px;
84
+ ">
85
+ {title}
86
+ </div>
87
+ {body}
88
+ </div>
89
+ """
90
+
91
+ # ==============================
92
+ # Number formatting
93
+ # ==============================
94
+ def format_number(x):
95
+ try:
96
+ x = float(x)
97
+ if abs(x) >= 100:
98
+ return f"{x:,.0f}"
99
+ if abs(x) >= 1:
100
+ return f"{x:,.2f}"
101
+ return f"{x:.4f}"
102
+ except:
103
+ return str(x)
104
+
105
+ # ==============================
106
+ # Compact inline table (Field : Value)
107
+ # ==============================
108
+ def make_table(df):
109
+ rows = ""
110
+ for _, r in df.iterrows():
111
+ val = r[1]
112
+ color = "#0d1f3c"
113
+
114
+ # Highlight change values
115
+ if any(x in r[0].lower() for x in ["chg", "%"]):
116
+ try:
117
+ color = "#0a7d32" if float(val) >= 0 else "#b00020"
118
+ except:
119
+ pass
120
+
121
+ rows += f"""
122
+ <div style="
123
+ display:flex;
124
+ justify-content:space-between;
125
+ gap:6px;
126
+ padding:2px 0;
127
+ border-bottom:1px dashed #bcd0ea;
128
+ ">
129
+ <span style="color:#1a4f8a;font-weight:500;white-space:nowrap;">
130
+ {r[0]}
131
+ </span>
132
+ <span style="
133
+ color:{color};
134
+ font-weight:600;
135
+ background:#f1f6ff;
136
+ padding:1px 6px;
137
+ border-radius:4px;
138
+ white-space:nowrap;
139
+ ">
140
+ {val}
141
+ </span>
142
+ </div>
143
+ """
144
+
145
+ return f"<div>{rows}</div>"
146
+
147
+ # ==============================
148
+ # Noise keys
149
+ # ==============================
150
+ NOISE_KEYS = {
151
+ "maxAge","priceHint","triggerable",
152
+ "customPriceAlertConfidence",
153
+ "sourceInterval","exchangeDataDelayedBy",
154
+ "esgPopulated"
155
+ }
156
+
157
+ def is_noise(k):
158
+ return k in NOISE_KEYS
159
+
160
+ # ==============================
161
+ # Duplicate resolution
162
+ # ==============================
163
+ DUPLICATE_PRIORITY = {
164
+ "price": ["regularMarketPrice","currentPrice"],
165
+ "prev": ["regularMarketPreviousClose","previousClose"],
166
+ "open": ["regularMarketOpen","open"],
167
+ "high": ["regularMarketDayHigh","dayHigh"],
168
+ "low": ["regularMarketDayLow","dayLow"],
169
+ "volume": ["regularMarketVolume","volume"]
170
+ }
171
+
172
+ def resolve_duplicates(data):
173
+ resolved, used = {}, set()
174
+ for keys in DUPLICATE_PRIORITY.values():
175
+ for k in keys:
176
+ if k in data:
177
+ resolved[k] = data[k]
178
+ used.update(keys)
179
+ break
180
+ for k,v in data.items():
181
+ if k not in used:
182
+ resolved[k] = v
183
+ return resolved
184
+
185
+ # ==============================
186
+ # Short names
187
+ # ==============================
188
+ SHORT_NAMES = {
189
+ "regularMarketPrice":"Price","regularMarketChange":"Chg",
190
+ "regularMarketChangePercent":"Chg%",
191
+ "regularMarketPreviousClose":"Prev",
192
+ "regularMarketOpen":"Open",
193
+ "regularMarketDayHigh":"High","regularMarketDayLow":"Low",
194
+ "regularMarketVolume":"Vol",
195
+ "averageDailyVolume10Day":"AvgV10",
196
+ "averageDailyVolume3Month":"AvgV3M",
197
+ "fiftyDayAverage":"50DMA","twoHundredDayAverage":"200DMA",
198
+ "fiftyTwoWeekLow":"52WL","fiftyTwoWeekHigh":"52WH",
199
+ "beta":"Beta","targetMeanPrice":"Target"
200
+ }
201
+
202
+ def pretty_key(k):
203
+ return SHORT_NAMES.get(k, k[:12])
204
+
205
+ # ==============================
206
+ # Classifiers
207
+ # ==============================
208
+ def classify_price_volume_subgroup(key):
209
+ k = key.lower()
210
+ if "volume" in k: return "Volume"
211
+ if "average" in k or "dma" in k: return "Moving Avg"
212
+ if "week" in k or "beta" in k: return "Range / Vol"
213
+ if "target" in k or "recommend" in k: return "Bid / Analyst"
214
+ return "Live Price"
215
+
216
+ def classify_key(key, value):
217
+ k = key.lower()
218
+ if isinstance(value,(int,float)) and any(x in k for x in [
219
+ "price","volume","avg","change","percent","market","week","beta","target"
220
+ ]):
221
+ return "price_volume"
222
+ if any(x in k for x in [
223
+ "revenue","income","profit","margin","pe","pb","roe","roa","debt","equity"
224
+ ]):
225
+ return "fundamental"
226
+ if isinstance(value,str) and len(value)>80:
227
+ return "long_text"
228
+ return "profile"
229
+
230
+ # ==============================
231
+ # Group builder
232
+ # ==============================
233
+ def build_grouped_info(info):
234
+ groups = {"price_volume":{}, "fundamental":{}, "profile":{}, "long_text":{}}
235
+ for k,v in info.items():
236
+ if v in [None,"",[],{}]: continue
237
+ groups[classify_key(k,v)][k] = v
238
+ return groups
239
+
240
+ # ==============================
241
+ # DataFrame builder
242
+ # ==============================
243
+ def build_df_from_dict(data):
244
+ rows=[]
245
+ for k,v in data.items():
246
+ if is_noise(k): continue
247
+ if isinstance(v,(int,float)):
248
+ v = format_number(v)
249
+ rows.append([pretty_key(k), v])
250
+ return pd.DataFrame(rows, columns=["Field","Value"])
251
+
252
+ # ==============================
253
+ # MAIN FUNCTION
254
+ # ==============================
255
+ def fetch_info(symbol):
256
+ try:
257
+ info = yfinfo(symbol)
258
+ if not info:
259
+ return "No data"
260
+
261
+ groups = build_grouped_info(info)
262
+ html = ""
263
+
264
+ # -------- PRICE / VOLUME --------
265
+ pv = resolve_duplicates(groups["price_volume"])
266
+ sub = {}
267
+ for k,v in pv.items():
268
+ sg = classify_price_volume_subgroup(k)
269
+ sub.setdefault(sg,{})[k] = v
270
+
271
+ cards = ""
272
+ for i,(t,d) in enumerate(sub.items()):
273
+ df = build_df_from_dict(d)
274
+ if not df.empty:
275
+ cards += html_card(
276
+ f"{SUBGROUP_ICONS.get(t,'ℹ️')} {t}",
277
+ make_table(df),
278
+ mini=True,
279
+ shade=i
280
+ )
281
+
282
+ if cards:
283
+ html += html_card(
284
+ f"{MAIN_ICONS['Price / Volume']} Price / Volume",
285
+ column_layout(cards),
286
+ shade=0
287
+ )
288
+
289
+ # -------- FUNDAMENTALS --------
290
+ if groups["fundamental"]:
291
+ html += html_card(
292
+ f"{MAIN_ICONS['Fundamentals']} Fundamentals",
293
+ make_table(build_df_from_dict(groups["fundamental"])),
294
+ shade=1
295
+ )
296
+
297
+ # -------- PROFILE --------
298
+ if groups["profile"]:
299
+ html += html_card(
300
+ f"{MAIN_ICONS['Company Profile']} Company Profile",
301
+ make_table(build_df_from_dict(groups["profile"])),
302
+ shade=2
303
+ )
304
+
305
+ # -------- LONG TEXT --------
306
+ for k,v in groups["long_text"].items():
307
+ html += html_card(pretty_key(k), v, shade=2)
308
+
309
+ return html
310
+
311
+ except Exception as e:
312
+ return f"<pre>{traceback.format_exc()}</pre>"