eshan6704 commited on
Commit
041eb08
·
verified ·
1 Parent(s): ac877b5

Update yahooinfo.py

Browse files
Files changed (1) hide show
  1. yahooinfo.py +79 -34
yahooinfo.py CHANGED
@@ -1,14 +1,23 @@
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
@@ -18,6 +27,7 @@ def yfinfo(symbol):
18
  except Exception as e:
19
  return {"__error__": str(e)}
20
 
 
21
  # ==============================
22
  # Icons
23
  # ==============================
@@ -36,6 +46,7 @@ MAIN_ICONS = {
36
  "Company Profile": "🏢"
37
  }
38
 
 
39
  # ==============================
40
  # Responsive column layout
41
  # ==============================
@@ -51,6 +62,7 @@ def column_layout(html, min_width=320):
51
  </div>
52
  """
53
 
 
54
  # ==============================
55
  # Card renderer
56
  # ==============================
@@ -88,8 +100,9 @@ def html_card(title, body, mini=False, shade=0):
88
  </div>
89
  """
90
 
 
91
  # ==============================
92
- # Formatting
93
  # ==============================
94
  def format_number(x):
95
  try:
@@ -102,6 +115,7 @@ def format_number(x):
102
  except:
103
  return str(x)
104
 
 
105
  # ==============================
106
  # Compact inline key:value view
107
  # ==============================
@@ -123,7 +137,7 @@ def make_table(df):
123
  padding:2px 0;
124
  border-bottom:1px dashed #bcd0ea;
125
  ">
126
- <span style="color:#1a4f8a;font-weight:500;white-space:nowrap;">
127
  {r[0]}
128
  </span>
129
  <span style="
@@ -132,7 +146,6 @@ def make_table(df):
132
  background:#f1f6ff;
133
  padding:1px 6px;
134
  border-radius:4px;
135
- white-space:nowrap;
136
  ">
137
  {r[1]}
138
  </span>
@@ -140,8 +153,9 @@ def make_table(df):
140
  """
141
  return f"<div>{rows}</div>"
142
 
 
143
  # ==============================
144
- # Noise keys
145
  # ==============================
146
  NOISE_KEYS = {
147
  "maxAge","priceHint","triggerable",
@@ -150,9 +164,10 @@ NOISE_KEYS = {
150
  "esgPopulated"
151
  }
152
 
153
- def is_noise(k):
154
  return k in NOISE_KEYS
155
 
 
156
  # ==============================
157
  # Duplicate resolver
158
  # ==============================
@@ -178,26 +193,33 @@ def resolve_duplicates(data):
178
  resolved[k] = v
179
  return resolved
180
 
 
181
  # ==============================
182
- # Short names
183
  # ==============================
184
  SHORT_NAMES = {
185
- "regularMarketPrice":"Price","regularMarketChange":"Chg",
 
186
  "regularMarketChangePercent":"Chg%",
187
  "regularMarketPreviousClose":"Prev",
188
  "regularMarketOpen":"Open",
189
- "regularMarketDayHigh":"High","regularMarketDayLow":"Low",
 
190
  "regularMarketVolume":"Vol",
191
  "averageDailyVolume10Day":"AvgV10",
192
  "averageDailyVolume3Month":"AvgV3M",
193
- "fiftyDayAverage":"50DMA","twoHundredDayAverage":"200DMA",
194
- "fiftyTwoWeekLow":"52WL","fiftyTwoWeekHigh":"52WH",
195
- "beta":"Beta","targetMeanPrice":"Target"
 
 
 
196
  }
197
 
198
  def pretty_key(k):
199
  return SHORT_NAMES.get(k, k[:12])
200
 
 
201
  # ==============================
202
  # Classifiers
203
  # ==============================
@@ -209,6 +231,7 @@ def classify_price_volume_subgroup(key):
209
  if "target" in k or "recommend" in k: return "Bid / Analyst"
210
  return "Live Price"
211
 
 
212
  def classify_key(key, value):
213
  k = key.lower()
214
  if isinstance(value,(int,float)) and any(x in k for x in [
@@ -219,64 +242,82 @@ def classify_key(key, value):
219
  "revenue","income","profit","margin","pe","pb","roe","roa","debt","equity"
220
  ]):
221
  return "fundamental"
222
- if isinstance(value,str) and len(value)>80:
223
  return "long_text"
224
  return "profile"
225
 
 
226
  # ==============================
227
  # Group builder
228
  # ==============================
229
  def build_grouped_info(info):
230
- groups = {"price_volume":{}, "fundamental":{}, "profile":{}, "long_text":{}}
 
 
 
 
 
231
  for k,v in info.items():
232
- if v in [None,"",[],{}]: continue
 
233
  groups[classify_key(k,v)][k] = v
234
  return groups
235
 
 
236
  # ==============================
237
- # Balanced column splitter (UTILISATION FIRST)
238
  # ==============================
239
  def split_df_evenly(df):
240
  if df is None or df.empty:
241
  return []
242
 
243
  n = len(df)
244
-
245
- if n <= 6:
246
- cols = 1
247
- elif n <= 14:
248
- cols = 2
249
- else:
250
- cols = 3
251
-
252
  chunk = (n + cols - 1) // cols
253
  return [df.iloc[i:i+chunk] for i in range(0, n, chunk)]
254
 
 
255
  # ==============================
256
  # DataFrame builder
257
  # ==============================
258
  def build_df_from_dict(data):
259
- rows=[]
260
  for k,v in data.items():
261
- if is_noise(k): continue
 
262
  if isinstance(v,(int,float)):
263
  v = format_number(v)
264
  rows.append([pretty_key(k), v])
265
  return pd.DataFrame(rows, columns=["Field","Value"])
266
 
 
267
  # ==============================
268
- # MAIN FUNCTION
269
  # ==============================
270
  def fetch_info(symbol):
 
 
 
 
 
 
 
 
 
 
 
 
271
  try:
272
  info = yfinfo(symbol)
273
- if not info:
 
 
274
  return "No data"
275
 
276
  groups = build_grouped_info(info)
277
  html = ""
278
 
279
- # -------- PRICE / VOLUME --------
280
  pv = resolve_duplicates(groups["price_volume"])
281
  sub = {}
282
  for k,v in pv.items():
@@ -301,7 +342,7 @@ def fetch_info(symbol):
301
  shade=0
302
  )
303
 
304
- # -------- FUNDAMENTALS --------
305
  if groups["fundamental"]:
306
  chunks = split_df_evenly(build_df_from_dict(groups["fundamental"]))
307
  cols = "".join(
@@ -314,7 +355,7 @@ def fetch_info(symbol):
314
  shade=1
315
  )
316
 
317
- # -------- COMPANY PROFILE --------
318
  if groups["profile"]:
319
  chunks = split_df_evenly(build_df_from_dict(groups["profile"]))
320
  cols = "".join(
@@ -327,11 +368,15 @@ def fetch_info(symbol):
327
  shade=2
328
  )
329
 
330
- # -------- LONG TEXT --------
331
  for k,v in groups["long_text"].items():
332
  html += html_card(pretty_key(k), v, shade=2)
333
 
 
 
 
 
334
  return html
335
 
336
  except Exception:
337
- return f"<pre>{traceback.format_exc()}</pre>"
 
1
  # ==============================
2
+ # Imports (kept same style)
3
  # ==============================
4
  import yfinance as yf
5
  import pandas as pd
6
  import traceback
7
+ import time
8
+
9
+ # persist helpers
10
+ from persist import exists, load, save
11
+
12
 
13
  # ==============================
14
+ # Yahoo Finance info fetch (RAW)
15
  # ==============================
16
  def yfinfo(symbol):
17
+ """
18
+ Low-level Yahoo Finance info fetch.
19
+ Returns raw dict or {"__error__": "..."}
20
+ """
21
  try:
22
  t = yf.Ticker(symbol + ".NS")
23
  info = t.info
 
27
  except Exception as e:
28
  return {"__error__": str(e)}
29
 
30
+
31
  # ==============================
32
  # Icons
33
  # ==============================
 
46
  "Company Profile": "🏢"
47
  }
48
 
49
+
50
  # ==============================
51
  # Responsive column layout
52
  # ==============================
 
62
  </div>
63
  """
64
 
65
+
66
  # ==============================
67
  # Card renderer
68
  # ==============================
 
100
  </div>
101
  """
102
 
103
+
104
  # ==============================
105
+ # Formatting helpers
106
  # ==============================
107
  def format_number(x):
108
  try:
 
115
  except:
116
  return str(x)
117
 
118
+
119
  # ==============================
120
  # Compact inline key:value view
121
  # ==============================
 
137
  padding:2px 0;
138
  border-bottom:1px dashed #bcd0ea;
139
  ">
140
+ <span style="color:#1a4f8a;font-weight:500;">
141
  {r[0]}
142
  </span>
143
  <span style="
 
146
  background:#f1f6ff;
147
  padding:1px 6px;
148
  border-radius:4px;
 
149
  ">
150
  {r[1]}
151
  </span>
 
153
  """
154
  return f"<div>{rows}</div>"
155
 
156
+
157
  # ==============================
158
+ # Noise filtering
159
  # ==============================
160
  NOISE_KEYS = {
161
  "maxAge","priceHint","triggerable",
 
164
  "esgPopulated"
165
  }
166
 
167
+ def is_noise(k):
168
  return k in NOISE_KEYS
169
 
170
+
171
  # ==============================
172
  # Duplicate resolver
173
  # ==============================
 
193
  resolved[k] = v
194
  return resolved
195
 
196
+
197
  # ==============================
198
+ # Short key names
199
  # ==============================
200
  SHORT_NAMES = {
201
+ "regularMarketPrice":"Price",
202
+ "regularMarketChange":"Chg",
203
  "regularMarketChangePercent":"Chg%",
204
  "regularMarketPreviousClose":"Prev",
205
  "regularMarketOpen":"Open",
206
+ "regularMarketDayHigh":"High",
207
+ "regularMarketDayLow":"Low",
208
  "regularMarketVolume":"Vol",
209
  "averageDailyVolume10Day":"AvgV10",
210
  "averageDailyVolume3Month":"AvgV3M",
211
+ "fiftyDayAverage":"50DMA",
212
+ "twoHundredDayAverage":"200DMA",
213
+ "fiftyTwoWeekLow":"52WL",
214
+ "fiftyTwoWeekHigh":"52WH",
215
+ "beta":"Beta",
216
+ "targetMeanPrice":"Target"
217
  }
218
 
219
  def pretty_key(k):
220
  return SHORT_NAMES.get(k, k[:12])
221
 
222
+
223
  # ==============================
224
  # Classifiers
225
  # ==============================
 
231
  if "target" in k or "recommend" in k: return "Bid / Analyst"
232
  return "Live Price"
233
 
234
+
235
  def classify_key(key, value):
236
  k = key.lower()
237
  if isinstance(value,(int,float)) and any(x in k for x in [
 
242
  "revenue","income","profit","margin","pe","pb","roe","roa","debt","equity"
243
  ]):
244
  return "fundamental"
245
+ if isinstance(value,str) and len(value) > 80:
246
  return "long_text"
247
  return "profile"
248
 
249
+
250
  # ==============================
251
  # Group builder
252
  # ==============================
253
  def build_grouped_info(info):
254
+ groups = {
255
+ "price_volume":{},
256
+ "fundamental":{},
257
+ "profile":{},
258
+ "long_text":{}
259
+ }
260
  for k,v in info.items():
261
+ if v in [None,"",[],{}]:
262
+ continue
263
  groups[classify_key(k,v)][k] = v
264
  return groups
265
 
266
+
267
  # ==============================
268
+ # Column splitter
269
  # ==============================
270
  def split_df_evenly(df):
271
  if df is None or df.empty:
272
  return []
273
 
274
  n = len(df)
275
+ cols = 1 if n <= 6 else 2 if n <= 14 else 3
 
 
 
 
 
 
 
276
  chunk = (n + cols - 1) // cols
277
  return [df.iloc[i:i+chunk] for i in range(0, n, chunk)]
278
 
279
+
280
  # ==============================
281
  # DataFrame builder
282
  # ==============================
283
  def build_df_from_dict(data):
284
+ rows = []
285
  for k,v in data.items():
286
+ if is_noise(k):
287
+ continue
288
  if isinstance(v,(int,float)):
289
  v = format_number(v)
290
  rows.append([pretty_key(k), v])
291
  return pd.DataFrame(rows, columns=["Field","Value"])
292
 
293
+
294
  # ==============================
295
+ # MAIN FUNCTION (CACHED)
296
  # ==============================
297
  def fetch_info(symbol):
298
+ """
299
+ Cached Yahoo Finance info renderer
300
+ Cache validity: 1 hour
301
+ """
302
+ key = f"info_{symbol}"
303
+
304
+ # ---------- CACHE CHECK ----------
305
+ if exists(key, "html"):
306
+ cached = load(key, "html", max_age=3600)
307
+ if cached:
308
+ return cached
309
+
310
  try:
311
  info = yfinfo(symbol)
312
+
313
+ # ---------- VALIDATION ----------
314
+ if not info or "__error__" in info:
315
  return "No data"
316
 
317
  groups = build_grouped_info(info)
318
  html = ""
319
 
320
+ # ---------- PRICE / VOLUME ----------
321
  pv = resolve_duplicates(groups["price_volume"])
322
  sub = {}
323
  for k,v in pv.items():
 
342
  shade=0
343
  )
344
 
345
+ # ---------- FUNDAMENTALS ----------
346
  if groups["fundamental"]:
347
  chunks = split_df_evenly(build_df_from_dict(groups["fundamental"]))
348
  cols = "".join(
 
355
  shade=1
356
  )
357
 
358
+ # ---------- COMPANY PROFILE ----------
359
  if groups["profile"]:
360
  chunks = split_df_evenly(build_df_from_dict(groups["profile"]))
361
  cols = "".join(
 
368
  shade=2
369
  )
370
 
371
+ # ---------- LONG TEXT ----------
372
  for k,v in groups["long_text"].items():
373
  html += html_card(pretty_key(k), v, shade=2)
374
 
375
+ # ---------- SAVE CACHE ----------
376
+ if html.strip():
377
+ save(key, html, "html")
378
+
379
  return html
380
 
381
  except Exception:
382
+ return f"<pre>{traceback.format_exc()}</pre>"