eshan6704 commited on
Commit
2cf0213
·
verified ·
1 Parent(s): 2ba9451

Create stock.py

Browse files
Files changed (1) hide show
  1. app/stock.py +386 -0
app/stock.py ADDED
@@ -0,0 +1,386 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ from backblaze import *
11
+ import ta_indi_pat
12
+
13
+
14
+ # ================================================================
15
+ # BASIC YFINANCE FETCHERS
16
+ # ================================================================
17
+
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
+ 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
+ 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:
163
+ df = qresult(symbol)
164
+ if df.empty:
165
+ return wrap_html(f"<h1>No quarterly results for {symbol}</h1>")
166
+
167
+ 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:
200
+ df = result(symbol)
201
+ if df.empty:
202
+ return wrap_html(f"<h1>No annual results for {symbol}</h1>")
203
+
204
+ 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:
237
+ df = balance(symbol)
238
+ if df.empty:
239
+ return wrap_html(f"<h1>No balance sheet for {symbol}</h1>")
240
+
241
+ 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:
274
+ df = cashflow(symbol)
275
+ if df.empty:
276
+ return wrap_html(f"<h1>No cashflow for {symbol}</h1>")
277
+
278
+ 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:
311
+ df = dividend(symbol)
312
+ if df.empty:
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:
341
+ df = split(symbol)
342
+ if df.empty:
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}"))