eshan6704 commited on
Commit
2fbe7eb
·
verified ·
1 Parent(s): b7d81a0

Update stock.py

Browse files
Files changed (1) hide show
  1. stock.py +164 -115
stock.py CHANGED
@@ -1,13 +1,15 @@
1
- # stock.py — compact, merged, single-file
2
- from common import *
3
- import yfinance as yf
4
- import pandas as pd
5
  import traceback
6
- from ta_indi_pat import *
7
- from persist import *
 
 
 
 
 
 
8
 
9
- #file_name = f"bhav/bhav_{date_str.replace('-', '_')}.csv"
10
- #upload_file("eshanhf",file_name,df)
11
 
12
  # ================================================================
13
  # BASIC YFINANCE FETCHERS
@@ -16,136 +18,145 @@ from persist import *
16
  def yfinfo(symbol):
17
  return yf.Ticker(symbol + ".NS").info
18
 
 
19
  def qresult(symbol):
20
-
21
  return yf.Ticker(symbol + ".NS").quarterly_financials
22
 
 
23
  def result(symbol):
24
  return yf.Ticker(symbol + ".NS").financials
25
 
 
26
  def balance(symbol):
27
  return yf.Ticker(symbol + ".NS").balance_sheet
28
 
 
29
  def cashflow(symbol):
30
  return yf.Ticker(symbol + ".NS").cashflow
31
 
 
32
  def dividend(symbol):
33
  return yf.Ticker(symbol + ".NS").dividends.to_frame("Dividend")
34
 
 
35
  def split(symbol):
36
  return yf.Ticker(symbol + ".NS").splits.to_frame("Split")
37
 
38
- from datetime import datetime
39
- import yfinance as yf
40
 
41
  def intraday(symbol):
42
- print(f"[{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] yf called for {symbol}")
43
  return yf.download(symbol + ".NS", period="1d", interval="5m").round(2)
44
 
45
 
46
  def daily(symbol):
47
- print(f"[{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] yf called for {symbol}")
48
  return yf.download(symbol + ".NS", period="1y", interval="1d").round(2)
49
 
50
 
51
  # ================================================================
52
- # FETCH INFO (USES COMMON.PY HELPERS)
53
  # ================================================================
54
 
55
- from common import (
56
- format_number,
57
- format_large_number,
58
- make_table,
59
- html_card,
60
- html_section,
61
- html_error,
62
- clean_df,
63
- safe_get,
64
- wrap_html
65
- )
66
-
67
- from chart_builder import build_chart
68
- from ta_indi_pat import talib_df
69
 
 
 
70
 
71
- def wrap_html(content, title="Market Data"):
72
- return f"<html><head><title>{title}</title></head><body>{content}</body></html>"
73
 
74
- def make_table(df: pd.DataFrame):
75
- return df.to_html(index=False)
76
- from datetime import datetime
77
- import pandas as pd
78
- import yfinance as yf
79
-
80
- # Assumes save, load, exists, upload_file, wrap_html, make_table, intraday, daily, result, qresult,
81
- # balance, cashflow, dividend, split, format_large_number, html_error are already defined
82
 
83
- # -------------------------- INTRADAY ------------------------------
84
  def fetch_intraday(symbol, indicators=None):
85
  key = f"intraday_{symbol}"
86
- if exists(key, "html"):
87
- cached = load(key, "html")
 
88
  if cached is not False:
89
- print(f"[{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] Using cached intraday for {symbol}")
90
  return cached
91
 
92
  try:
93
  df = intraday(symbol)
94
- if df is False or df is None or df.empty:
95
  return wrap_html(f"<h1>No intraday data for {symbol}</h1>")
96
 
97
  if isinstance(df.columns, pd.MultiIndex):
98
  df.columns = df.columns.get_level_values(0)
99
 
100
- # Optional upload
101
- upload_file("eshanhf", f"intraday/{symbol}.csv", df)
102
 
103
- # Preserve index in HTML
104
  df_display = df.tail(50).copy()
105
  df_display.reset_index(inplace=True)
106
- html = wrap_html(f"<h2>Last 50 Rows</h2>{make_table(df_display)}", title=f"{symbol} Intraday")
107
 
108
- save(key, html, "html")
 
 
 
 
 
109
  return html
 
110
  except Exception as e:
111
- print(f"[{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] Error fetch_intraday: {e}")
112
  return wrap_html(f"<h1>Error: {e}</h1>")
113
 
114
 
115
- # -------------------------- DAILY ------------------------------
 
 
 
116
  def fetch_daily(symbol):
117
  key = f"daily_{symbol}"
118
- if exists(key, "html"):
119
- cached = load(key, "html")
 
120
  if cached is not False:
121
- print(f"[{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] Using cached daily for {symbol}")
122
  return cached
123
 
124
  try:
125
  df = daily(symbol)
126
- if df is False or df is None or df.empty:
127
  return wrap_html(f"<h1>No daily data for {symbol}</h1>")
128
 
129
- upload_file("eshanhf", f"daily/{symbol}.csv", df)
130
 
131
  df_display = df.tail(50).copy()
132
  df_display.reset_index(inplace=True)
133
- html = wrap_html(f"<h2>Last 50 Rows</h2>{make_table(df_display)}", title=f"{symbol} Daily")
134
 
135
- save(key, html, "html")
 
 
 
 
 
136
  return html
 
137
  except Exception as e:
138
- print(f"[{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] Error fetch_daily: {e}")
139
  return wrap_html(f"<h1>Error: {e}</h1>")
140
 
141
 
142
- # -------------------------- QUARTERLY ------------------------------
 
 
 
143
  def fetch_qresult(symbol):
144
  key = f"qresult_{symbol}"
145
- if exists(key, "html"):
146
- cached = load(key, "html")
 
147
  if cached is not False:
148
- print(f"[{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] Using cached quarterly for {symbol}")
149
  return cached
150
 
151
  try:
@@ -153,28 +164,36 @@ def fetch_qresult(symbol):
153
  if df.empty:
154
  return wrap_html(f"<h1>No quarterly results for {symbol}</h1>")
155
 
156
- upload_file("eshanhf", f"qresult/{symbol}.csv", df)
157
 
158
  df_display = df.copy()
159
  for col in df_display.columns:
160
- df_display[col] = df_display[col].apply(lambda x: format_large_number(x) if isinstance(x, (int, float)) else x)
161
- df_display.reset_index(inplace=True) # preserve original index
 
 
 
162
 
163
  html = wrap_html(make_table(df_display), title=f"{symbol} Quarterly Results")
164
- save(key, html, "html")
165
  return html
 
166
  except Exception as e:
167
- print(f"[{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] Error fetch_qresult: {e}")
168
  return wrap_html(html_error(f"Quarterly Error: {e}"))
169
 
170
 
171
- # -------------------------- ANNUAL ------------------------------
 
 
 
172
  def fetch_result(symbol):
173
  key = f"result_{symbol}"
174
- if exists(key, "html"):
175
- cached = load(key, "html")
 
176
  if cached is not False:
177
- print(f"[{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] Using cached annual for {symbol}")
178
  return cached
179
 
180
  try:
@@ -182,28 +201,36 @@ def fetch_result(symbol):
182
  if df.empty:
183
  return wrap_html(f"<h1>No annual results for {symbol}</h1>")
184
 
185
- upload_file("eshanhf", f"result/{symbol}.csv", df)
186
 
187
  df_display = df.copy()
188
  for col in df_display.columns:
189
- df_display[col] = df_display[col].apply(lambda x: format_large_number(x) if isinstance(x, (int, float)) else x)
 
 
 
190
  df_display.reset_index(inplace=True)
191
 
192
  html = wrap_html(make_table(df_display), title=f"{symbol} Annual Results")
193
- save(key, html, "html")
194
  return html
 
195
  except Exception as e:
196
- print(f"[{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] Error fetch_result: {e}")
197
  return wrap_html(html_error(f"Annual Error: {e}"))
198
 
199
 
200
- # -------------------------- BALANCE ------------------------------
 
 
 
201
  def fetch_balance(symbol):
202
  key = f"balance_{symbol}"
203
- if exists(key, "html"):
204
- cached = load(key, "html")
 
205
  if cached is not False:
206
- print(f"[{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] Using cached balance for {symbol}")
207
  return cached
208
 
209
  try:
@@ -211,28 +238,36 @@ def fetch_balance(symbol):
211
  if df.empty:
212
  return wrap_html(f"<h1>No balance sheet for {symbol}</h1>")
213
 
214
- upload_file("eshanhf", f"balance/{symbol}.csv", df)
215
 
216
  df_display = df.copy()
217
  for col in df_display.columns:
218
- df_display[col] = df_display[col].apply(lambda x: format_large_number(x) if isinstance(x, (int, float)) else x)
 
 
 
219
  df_display.reset_index(inplace=True)
220
 
221
  html = wrap_html(make_table(df_display), title=f"{symbol} Balance Sheet")
222
- save(key, html, "html")
223
  return html
 
224
  except Exception as e:
225
- print(f"[{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] Error fetch_balance: {e}")
226
  return wrap_html(html_error(f"Balance Error: {e}"))
227
 
228
 
229
- # -------------------------- CASHFLOW ------------------------------
 
 
 
230
  def fetch_cashflow(symbol):
231
  key = f"cashflow_{symbol}"
232
- if exists(key, "html"):
233
- cached = load(key, "html")
 
234
  if cached is not False:
235
- print(f"[{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] Using cached cashflow for {symbol}")
236
  return cached
237
 
238
  try:
@@ -240,28 +275,36 @@ def fetch_cashflow(symbol):
240
  if df.empty:
241
  return wrap_html(f"<h1>No cashflow for {symbol}</h1>")
242
 
243
- upload_file("eshanhf", f"cashflow/{symbol}.csv", df)
244
 
245
  df_display = df.copy()
246
  for col in df_display.columns:
247
- df_display[col] = df_display[col].apply(lambda x: format_large_number(x) if isinstance(x, (int, float)) else x)
 
 
 
248
  df_display.reset_index(inplace=True)
249
 
250
  html = wrap_html(make_table(df_display), title=f"{symbol} Cash Flow")
251
- save(key, html, "html")
252
  return html
 
253
  except Exception as e:
254
- print(f"[{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] Error fetch_cashflow: {e}")
255
  return wrap_html(html_error(f"Cash Flow Error: {e}"))
256
 
257
 
258
- # -------------------------- DIVIDEND ------------------------------
 
 
 
259
  def fetch_dividend(symbol):
260
  key = f"dividend_{symbol}"
261
- if exists(key, "html"):
262
- cached = load(key, "html")
 
263
  if cached is not False:
264
- print(f"[{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] Using cached dividend for {symbol}")
265
  return cached
266
 
267
  try:
@@ -270,25 +313,28 @@ def fetch_dividend(symbol):
270
  return wrap_html(f"<h1>No dividend history for {symbol}</h1>")
271
 
272
  df_display = df.copy()
273
- for col in df_display.columns:
274
- df_display[col] = df_display[col].apply(lambda x: format_large_number(x) if isinstance(x, (int, float)) else x)
275
  df_display.reset_index(inplace=True)
276
 
277
  html = wrap_html(make_table(df_display), title=f"{symbol} Dividends")
278
- save(key, html, "html")
279
  return html
 
280
  except Exception as e:
281
- print(f"[{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] Error fetch_dividend: {e}")
282
  return wrap_html(html_error(f"Dividend Error: {e}"))
283
 
284
 
285
- # -------------------------- SPLIT ------------------------------
 
 
 
286
  def fetch_split(symbol):
287
  key = f"split_{symbol}"
288
- if exists(key, "html"):
289
- cached = load(key, "html")
 
290
  if cached is not False:
291
- print(f"[{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] Using cached split for {symbol}")
292
  return cached
293
 
294
  try:
@@ -297,41 +343,44 @@ def fetch_split(symbol):
297
  return wrap_html(f"<h1>No splits for {symbol}</h1>")
298
 
299
  df_display = df.copy()
300
- for col in df_display.columns:
301
- df_display[col] = df_display[col].apply(lambda x: format_large_number(x) if isinstance(x, (int, float)) else x)
302
  df_display.reset_index(inplace=True)
303
 
304
  html = wrap_html(make_table(df_display), title=f"{symbol} Splits")
305
- save(key, html, "html")
306
  return html
 
307
  except Exception as e:
308
- print(f"[{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] Error fetch_split: {e}")
309
  return wrap_html(html_error(f"Split Error: {e}"))
310
 
311
 
312
- # -------------------------- OTHER (EARNINGS) ------------------------------
 
 
 
313
  def fetch_other(symbol):
314
  key = f"other_{symbol}"
315
- if exists(key, "html"):
316
- cached = load(key, "html")
 
317
  if cached is not False:
318
- print(f"[{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] Using cached earnings for {symbol}")
319
  return cached
320
 
321
  try:
322
  ticker = yf.Ticker(symbol + ".NS")
323
  df = ticker.earnings
 
324
  if df.empty:
325
  return wrap_html(f"<h1>No earnings data for {symbol}</h1>")
326
 
327
  df_display = df.copy()
328
- for col in df_display.columns:
329
- df_display[col] = df_display[col].apply(lambda x: format_large_number(x) if isinstance(x, (int, float)) else x)
330
  df_display.reset_index(inplace=True)
331
 
332
  html = wrap_html(make_table(df_display), title=f"{symbol} Earnings")
333
- save(key, html, "html")
334
  return html
 
335
  except Exception as e:
336
- print(f"[{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] Error fetch_other: {e}")
337
  return wrap_html(html_error(f"Earnings Error: {e}"))
 
1
+ # stock.py — compact, merged, single-file (collision-safe)
2
+
 
 
3
  import traceback
4
+ import pandas as pd
5
+ import yfinance as yf
6
+ from datetime import datetime as dt
7
+
8
+ import persist
9
+ import common
10
+ import chart_builder
11
+ import ta_indi_pat
12
 
 
 
13
 
14
  # ================================================================
15
  # BASIC YFINANCE FETCHERS
 
18
  def yfinfo(symbol):
19
  return yf.Ticker(symbol + ".NS").info
20
 
21
+
22
  def qresult(symbol):
 
23
  return yf.Ticker(symbol + ".NS").quarterly_financials
24
 
25
+
26
  def result(symbol):
27
  return yf.Ticker(symbol + ".NS").financials
28
 
29
+
30
  def balance(symbol):
31
  return yf.Ticker(symbol + ".NS").balance_sheet
32
 
33
+
34
  def cashflow(symbol):
35
  return yf.Ticker(symbol + ".NS").cashflow
36
 
37
+
38
  def dividend(symbol):
39
  return yf.Ticker(symbol + ".NS").dividends.to_frame("Dividend")
40
 
41
+
42
  def split(symbol):
43
  return yf.Ticker(symbol + ".NS").splits.to_frame("Split")
44
 
 
 
45
 
46
  def intraday(symbol):
47
+ print(f"[{dt.now().strftime('%Y-%m-%d %H:%M:%S')}] yf called for {symbol}")
48
  return yf.download(symbol + ".NS", period="1d", interval="5m").round(2)
49
 
50
 
51
  def daily(symbol):
52
+ print(f"[{dt.now().strftime('%Y-%m-%d %H:%M:%S')}] yf called for {symbol}")
53
  return yf.download(symbol + ".NS", period="1y", interval="1d").round(2)
54
 
55
 
56
  # ================================================================
57
+ # HTML HELPERS (delegated to common)
58
  # ================================================================
59
 
60
+ format_number = common.format_number
61
+ format_large_number = common.format_large_number
62
+ make_table = common.make_table
63
+ html_card = common.html_card
64
+ html_section = common.html_section
65
+ html_error = common.html_error
66
+ clean_df = common.clean_df
67
+ safe_get = common.safe_get
68
+ wrap_html = common.wrap_html
 
 
 
 
 
69
 
70
+ build_chart = chart_builder.build_chart
71
+ talib_df = ta_indi_pat.talib_df
72
 
 
 
73
 
74
+ # ================================================================
75
+ # INTRADAY
76
+ # ================================================================
 
 
 
 
 
77
 
 
78
  def fetch_intraday(symbol, indicators=None):
79
  key = f"intraday_{symbol}"
80
+
81
+ if persist.exists(key, "html"):
82
+ cached = persist.load(key, "html")
83
  if cached is not False:
84
+ print(f"[{dt.now().strftime('%Y-%m-%d %H:%M:%S')}] Using cached intraday for {symbol}")
85
  return cached
86
 
87
  try:
88
  df = intraday(symbol)
89
+ if df is None or df is False or df.empty:
90
  return wrap_html(f"<h1>No intraday data for {symbol}</h1>")
91
 
92
  if isinstance(df.columns, pd.MultiIndex):
93
  df.columns = df.columns.get_level_values(0)
94
 
95
+ persist.upload_file("eshanhf", f"intraday/{symbol}.csv", df)
 
96
 
 
97
  df_display = df.tail(50).copy()
98
  df_display.reset_index(inplace=True)
 
99
 
100
+ html = wrap_html(
101
+ f"<h2>Last 50 Rows</h2>{make_table(df_display)}",
102
+ title=f"{symbol} Intraday"
103
+ )
104
+
105
+ persist.save(key, html, "html")
106
  return html
107
+
108
  except Exception as e:
109
+ print(f"[{dt.now().strftime('%Y-%m-%d %H:%M:%S')}] Error fetch_intraday: {e}")
110
  return wrap_html(f"<h1>Error: {e}</h1>")
111
 
112
 
113
+ # ================================================================
114
+ # DAILY
115
+ # ================================================================
116
+
117
  def fetch_daily(symbol):
118
  key = f"daily_{symbol}"
119
+
120
+ if persist.exists(key, "html"):
121
+ cached = persist.load(key, "html")
122
  if cached is not False:
123
+ print(f"[{dt.now().strftime('%Y-%m-%d %H:%M:%S')}] Using cached daily for {symbol}")
124
  return cached
125
 
126
  try:
127
  df = daily(symbol)
128
+ if df is None or df is False or df.empty:
129
  return wrap_html(f"<h1>No daily data for {symbol}</h1>")
130
 
131
+ persist.upload_file("eshanhf", f"daily/{symbol}.csv", df)
132
 
133
  df_display = df.tail(50).copy()
134
  df_display.reset_index(inplace=True)
 
135
 
136
+ html = wrap_html(
137
+ f"<h2>Last 50 Rows</h2>{make_table(df_display)}",
138
+ title=f"{symbol} Daily"
139
+ )
140
+
141
+ persist.save(key, html, "html")
142
  return html
143
+
144
  except Exception as e:
145
+ print(f"[{dt.now().strftime('%Y-%m-%d %H:%M:%S')}] Error fetch_daily: {e}")
146
  return wrap_html(f"<h1>Error: {e}</h1>")
147
 
148
 
149
+ # ================================================================
150
+ # QUARTERLY
151
+ # ================================================================
152
+
153
  def fetch_qresult(symbol):
154
  key = f"qresult_{symbol}"
155
+
156
+ if persist.exists(key, "html"):
157
+ cached = persist.load(key, "html")
158
  if cached is not False:
159
+ print(f"[{dt.now().strftime('%Y-%m-%d %H:%M:%S')}] Using cached quarterly for {symbol}")
160
  return cached
161
 
162
  try:
 
164
  if df.empty:
165
  return wrap_html(f"<h1>No quarterly results for {symbol}</h1>")
166
 
167
+ persist.upload_file("eshanhf", f"qresult/{symbol}.csv", df)
168
 
169
  df_display = df.copy()
170
  for col in df_display.columns:
171
+ df_display[col] = df_display[col].apply(
172
+ lambda x: format_large_number(x) if isinstance(x, (int, float)) else x
173
+ )
174
+
175
+ df_display.reset_index(inplace=True)
176
 
177
  html = wrap_html(make_table(df_display), title=f"{symbol} Quarterly Results")
178
+ persist.save(key, html, "html")
179
  return html
180
+
181
  except Exception as e:
182
+ print(f"[{dt.now().strftime('%Y-%m-%d %H:%M:%S')}] Error fetch_qresult: {e}")
183
  return wrap_html(html_error(f"Quarterly Error: {e}"))
184
 
185
 
186
+ # ================================================================
187
+ # ANNUAL
188
+ # ================================================================
189
+
190
  def fetch_result(symbol):
191
  key = f"result_{symbol}"
192
+
193
+ if persist.exists(key, "html"):
194
+ cached = persist.load(key, "html")
195
  if cached is not False:
196
+ print(f"[{dt.now().strftime('%Y-%m-%d %H:%M:%S')}] Using cached annual for {symbol}")
197
  return cached
198
 
199
  try:
 
201
  if df.empty:
202
  return wrap_html(f"<h1>No annual results for {symbol}</h1>")
203
 
204
+ persist.upload_file("eshanhf", f"result/{symbol}.csv", df)
205
 
206
  df_display = df.copy()
207
  for col in df_display.columns:
208
+ df_display[col] = df_display[col].apply(
209
+ lambda x: format_large_number(x) if isinstance(x, (int, float)) else x
210
+ )
211
+
212
  df_display.reset_index(inplace=True)
213
 
214
  html = wrap_html(make_table(df_display), title=f"{symbol} Annual Results")
215
+ persist.save(key, html, "html")
216
  return html
217
+
218
  except Exception as e:
219
+ print(f"[{dt.now().strftime('%Y-%m-%d %H:%M:%S')}] Error fetch_result: {e}")
220
  return wrap_html(html_error(f"Annual Error: {e}"))
221
 
222
 
223
+ # ================================================================
224
+ # BALANCE SHEET
225
+ # ================================================================
226
+
227
  def fetch_balance(symbol):
228
  key = f"balance_{symbol}"
229
+
230
+ if persist.exists(key, "html"):
231
+ cached = persist.load(key, "html")
232
  if cached is not False:
233
+ print(f"[{dt.now().strftime('%Y-%m-%d %H:%M:%S')}] Using cached balance for {symbol}")
234
  return cached
235
 
236
  try:
 
238
  if df.empty:
239
  return wrap_html(f"<h1>No balance sheet for {symbol}</h1>")
240
 
241
+ persist.upload_file("eshanhf", f"balance/{symbol}.csv", df)
242
 
243
  df_display = df.copy()
244
  for col in df_display.columns:
245
+ df_display[col] = df_display[col].apply(
246
+ lambda x: format_large_number(x) if isinstance(x, (int, float)) else x
247
+ )
248
+
249
  df_display.reset_index(inplace=True)
250
 
251
  html = wrap_html(make_table(df_display), title=f"{symbol} Balance Sheet")
252
+ persist.save(key, html, "html")
253
  return html
254
+
255
  except Exception as e:
256
+ print(f"[{dt.now().strftime('%Y-%m-%d %H:%M:%S')}] Error fetch_balance: {e}")
257
  return wrap_html(html_error(f"Balance Error: {e}"))
258
 
259
 
260
+ # ================================================================
261
+ # CASHFLOW
262
+ # ================================================================
263
+
264
  def fetch_cashflow(symbol):
265
  key = f"cashflow_{symbol}"
266
+
267
+ if persist.exists(key, "html"):
268
+ cached = persist.load(key, "html")
269
  if cached is not False:
270
+ print(f"[{dt.now().strftime('%Y-%m-%d %H:%M:%S')}] Using cached cashflow for {symbol}")
271
  return cached
272
 
273
  try:
 
275
  if df.empty:
276
  return wrap_html(f"<h1>No cashflow for {symbol}</h1>")
277
 
278
+ persist.upload_file("eshanhf", f"cashflow/{symbol}.csv", df)
279
 
280
  df_display = df.copy()
281
  for col in df_display.columns:
282
+ df_display[col] = df_display[col].apply(
283
+ lambda x: format_large_number(x) if isinstance(x, (int, float)) else x
284
+ )
285
+
286
  df_display.reset_index(inplace=True)
287
 
288
  html = wrap_html(make_table(df_display), title=f"{symbol} Cash Flow")
289
+ persist.save(key, html, "html")
290
  return html
291
+
292
  except Exception as e:
293
+ print(f"[{dt.now().strftime('%Y-%m-%d %H:%M:%S')}] Error fetch_cashflow: {e}")
294
  return wrap_html(html_error(f"Cash Flow Error: {e}"))
295
 
296
 
297
+ # ================================================================
298
+ # DIVIDEND
299
+ # ================================================================
300
+
301
  def fetch_dividend(symbol):
302
  key = f"dividend_{symbol}"
303
+
304
+ if persist.exists(key, "html"):
305
+ cached = persist.load(key, "html")
306
  if cached is not False:
307
+ print(f"[{dt.now().strftime('%Y-%m-%d %H:%M:%S')}] Using cached dividend for {symbol}")
308
  return cached
309
 
310
  try:
 
313
  return wrap_html(f"<h1>No dividend history for {symbol}</h1>")
314
 
315
  df_display = df.copy()
 
 
316
  df_display.reset_index(inplace=True)
317
 
318
  html = wrap_html(make_table(df_display), title=f"{symbol} Dividends")
319
+ persist.save(key, html, "html")
320
  return html
321
+
322
  except Exception as e:
323
+ print(f"[{dt.now().strftime('%Y-%m-%d %H:%M:%S')}] Error fetch_dividend: {e}")
324
  return wrap_html(html_error(f"Dividend Error: {e}"))
325
 
326
 
327
+ # ================================================================
328
+ # SPLIT
329
+ # ================================================================
330
+
331
  def fetch_split(symbol):
332
  key = f"split_{symbol}"
333
+
334
+ if persist.exists(key, "html"):
335
+ cached = persist.load(key, "html")
336
  if cached is not False:
337
+ print(f"[{dt.now().strftime('%Y-%m-%d %H:%M:%S')}] Using cached split for {symbol}")
338
  return cached
339
 
340
  try:
 
343
  return wrap_html(f"<h1>No splits for {symbol}</h1>")
344
 
345
  df_display = df.copy()
 
 
346
  df_display.reset_index(inplace=True)
347
 
348
  html = wrap_html(make_table(df_display), title=f"{symbol} Splits")
349
+ persist.save(key, html, "html")
350
  return html
351
+
352
  except Exception as e:
353
+ print(f"[{dt.now().strftime('%Y-%m-%d %H:%M:%S')}] Error fetch_split: {e}")
354
  return wrap_html(html_error(f"Split Error: {e}"))
355
 
356
 
357
+ # ================================================================
358
+ # EARNINGS
359
+ # ================================================================
360
+
361
  def fetch_other(symbol):
362
  key = f"other_{symbol}"
363
+
364
+ if persist.exists(key, "html"):
365
+ cached = persist.load(key, "html")
366
  if cached is not False:
367
+ print(f"[{dt.now().strftime('%Y-%m-%d %H:%M:%S')}] Using cached earnings for {symbol}")
368
  return cached
369
 
370
  try:
371
  ticker = yf.Ticker(symbol + ".NS")
372
  df = ticker.earnings
373
+
374
  if df.empty:
375
  return wrap_html(f"<h1>No earnings data for {symbol}</h1>")
376
 
377
  df_display = df.copy()
 
 
378
  df_display.reset_index(inplace=True)
379
 
380
  html = wrap_html(make_table(df_display), title=f"{symbol} Earnings")
381
+ persist.save(key, html, "html")
382
  return html
383
+
384
  except Exception as e:
385
+ print(f"[{dt.now().strftime('%Y-%m-%d %H:%M:%S')}] Error fetch_other: {e}")
386
  return wrap_html(html_error(f"Earnings Error: {e}"))