# stock.py — compact, merged, single-file (collision-safe)
import traceback
import pandas as pd
import yfinance as yf
from datetime import datetime as dt
# persist helpers
from . import persist
from .common import *
from . import backblaze as b2
from . import ta_indi_pat
# ================================================================
# BASIC YFINANCE FETCHERS
# ================================================================
def yfinfo(symbol):
return yf.Ticker(symbol + ".NS").info
def qresult(symbol):
return yf.Ticker(symbol + ".NS").quarterly_financials
def result(symbol):
return yf.Ticker(symbol + ".NS").financials
def balance(symbol):
return yf.Ticker(symbol + ".NS").balance_sheet
def cashflow(symbol):
return yf.Ticker(symbol + ".NS").cashflow
def dividend(symbol):
return yf.Ticker(symbol + ".NS").dividends.to_frame("Dividend")
def split(symbol):
return yf.Ticker(symbol + ".NS").splits.to_frame("Split")
def intraday(symbol):
print(f"[{dt.now().strftime('%Y-%m-%d %H:%M:%S')}] yf called for {symbol}")
return yf.download(symbol + ".NS", period="1d", interval="5m").round(2)
def daily(symbol,date_end,date_start):
print(f"[{dt.now().strftime('%Y-%m-%d %H:%M:%S')}] yf called for {symbol}")
start = dt.strptime(date_start, "%d-%m-%Y").strftime("%Y-%m-%d")
end = dt.strptime(date_end, "%d-%m-%Y").strftime("%Y-%m-%d")
return yf.download(symbol + ".NS", start=start,end=end).round(2)
# ================================================================
# INTRADAY
# ================================================================
def fetch_intraday(symbol, indicators=None,b2_save=False):
key = f"intraday_{symbol}"
if persist.exists(key, "html"):
cached = persist.load(key, "html")
if cached is not False:
print(f"[{dt.now().strftime('%Y-%m-%d %H:%M:%S')}] Using cached intraday for {symbol}")
return cached
try:
df = intraday(symbol)
if df is None or df is False or df.empty:
return wrap_html(f"
No intraday data for {symbol}
")
if isinstance(df.columns, pd.MultiIndex):
df.columns = df.columns.get_level_values(0)
if b2_save:
b2.upload_file("eshanhf", f"intraday/{symbol}.csv", df)
df_display = df.copy()
df_display.reset_index(inplace=True)
html = wrap_html(
f"Last 50 Rows
{make_table(df_display)}",
title=f"{symbol} Intraday"
)
persist.save(key, html, "html")
return html
except Exception as e:
print(f"[{dt.now().strftime('%Y-%m-%d %H:%M:%S')}] Error fetch_intraday: {e}")
return wrap_html(f"Error: {e}
")
# ================================================================
# DAILY
# ================================================================
def fetch_daily(symbol,date_end,date_start,b2_save=False):
key = f"daily_{symbol}"
if persist.exists(key, "html"):
cached = persist.load(key, "html")
if cached is not False:
print(f"[{date_end}] Using cached daily for {symbol}")
return cached
try:
df = daily(symbol,date_end,date_start)
if df is None or df is False or df.empty:
return wrap_html(f"No daily data for {symbol}
")
if isinstance(df.columns, pd.MultiIndex):
df.columns = df.columns.get_level_values(0)
if b2_save:
b2.upload_file("eshanhf", f"intraday/{symbol}.csv", df)
df_display = df.copy()
df_display.reset_index(inplace=True)
html = wrap_html(
f"Last 50 Rows
{make_table(df_display)}",
title=f"{symbol} Daily"
)
persist.save(key, html, "html")
return html
except Exception as e:
print(f"[{dt.now().strftime('%Y-%m-%d %H:%M:%S')}] Error fetch_daily: {e}")
return wrap_html(f"Error: {e}
")
# ================================================================
# QUARTERLY
# ================================================================
def fetch_qresult(symbol,b2_save=False):
key = f"qresult_{symbol}"
if persist.exists(key, "html"):
cached = persist.load(key, "html")
if cached is not False:
print(f"[{dt.now().strftime('%Y-%m-%d %H:%M:%S')}] Using cached quarterly for {symbol}")
return cached
try:
df = qresult(symbol)
if df.empty:
return wrap_html(f"No quarterly results for {symbol}
")
if b2_save:
b2.upload_file("eshanhf", f"intraday/{symbol}.csv", df)
df_display = df.copy()
for col in df_display.columns:
df_display[col] = df_display[col].apply(
lambda x: format_large_number(x) if isinstance(x, (int, float)) else x
)
df_display.reset_index(inplace=True)
html = wrap_html(make_table(df_display), title=f"{symbol} Quarterly Results")
persist.save(key, html, "html")
return html
except Exception as e:
print(f"[{dt.now().strftime('%Y-%m-%d %H:%M:%S')}] Error fetch_qresult: {e}")
return wrap_html(html_error(f"Quarterly Error: {e}"))
# ================================================================
# ANNUAL
# ================================================================
def fetch_result(symbol,b2_save=False):
key = f"result_{symbol}"
if persist.exists(key, "html"):
cached = persist.load(key, "html")
if cached is not False:
print(f"[{dt.now().strftime('%Y-%m-%d %H:%M:%S')}] Using cached annual for {symbol}")
return cached
try:
df = result(symbol)
if df.empty:
return wrap_html(f"No annual results for {symbol}
")
if b2_save:
b2.upload_file("eshanhf", f"intraday/{symbol}.csv", df)
df_display = df.copy()
for col in df_display.columns:
df_display[col] = df_display[col].apply(
lambda x: format_large_number(x) if isinstance(x, (int, float)) else x
)
df_display.reset_index(inplace=True)
html = wrap_html(make_table(df_display), title=f"{symbol} Annual Results")
persist.save(key, html, "html")
return html
except Exception as e:
print(f"[{dt.now().strftime('%Y-%m-%d %H:%M:%S')}] Error fetch_result: {e}")
return wrap_html(html_error(f"Annual Error: {e}"))
# ================================================================
# BALANCE SHEET
# ================================================================
def fetch_balance(symbol,b2_save=False):
key = f"balance_{symbol}"
if persist.exists(key, "html"):
cached = persist.load(key, "html")
if cached is not False:
print(f"[{dt.now().strftime('%Y-%m-%d %H:%M:%S')}] Using cached balance for {symbol}")
return cached
try:
df = balance(symbol)
if df.empty:
return wrap_html(f"No balance sheet for {symbol}
")
if b2_save:
b2.upload_file("eshanhf", f"intraday/{symbol}.csv", df)
df_display = df.copy()
for col in df_display.columns:
df_display[col] = df_display[col].apply(
lambda x: format_large_number(x) if isinstance(x, (int, float)) else x
)
df_display.reset_index(inplace=True)
html = wrap_html(make_table(df_display), title=f"{symbol} Balance Sheet")
persist.save(key, html, "html")
return html
except Exception as e:
print(f"[{dt.now().strftime('%Y-%m-%d %H:%M:%S')}] Error fetch_balance: {e}")
return wrap_html(html_error(f"Balance Error: {e}"))
# ================================================================
# CASHFLOW
# ================================================================
def fetch_cashflow(symbol,b2_save=False):
key = f"cashflow_{symbol}"
if persist.exists(key, "html"):
cached = persist.load(key, "html")
if cached is not False:
print(f"[{dt.now().strftime('%Y-%m-%d %H:%M:%S')}] Using cached cashflow for {symbol}")
return cached
try:
df = cashflow(symbol)
if df.empty:
return wrap_html(f"No cashflow for {symbol}
")
if b2_save:
b2.upload_file("eshanhf", f"intraday/{symbol}.csv", df)
df_display = df.copy()
for col in df_display.columns:
df_display[col] = df_display[col].apply(
lambda x: format_large_number(x) if isinstance(x, (int, float)) else x
)
df_display.reset_index(inplace=True)
html = wrap_html(make_table(df_display), title=f"{symbol} Cash Flow")
persist.save(key, html, "html")
return html
except Exception as e:
print(f"[{dt.now().strftime('%Y-%m-%d %H:%M:%S')}] Error fetch_cashflow: {e}")
return wrap_html(html_error(f"Cash Flow Error: {e}"))
# ================================================================
# DIVIDEND
# ================================================================
def fetch_dividend(symbol,b2_save=False):
key = f"dividend_{symbol}"
if persist.exists(key, "html"):
cached = persist.load(key, "html")
if cached is not False:
print(f"[{dt.now().strftime('%Y-%m-%d %H:%M:%S')}] Using cached dividend for {symbol}")
return cached
try:
df = dividend(symbol)
if df.empty:
return wrap_html(f"No dividend history for {symbol}
")
df_display = df.copy()
df_display.reset_index(inplace=True)
if b2_save:
b2.upload_file("eshanhf", f"intraday/{symbol}.csv", df)
html = wrap_html(make_table(df_display), title=f"{symbol} Dividends")
persist.save(key, html, "html")
return html
except Exception as e:
print(f"[{dt.now().strftime('%Y-%m-%d %H:%M:%S')}] Error fetch_dividend: {e}")
return wrap_html(html_error(f"Dividend Error: {e}"))
# ================================================================
# SPLIT
# ================================================================
def fetch_split(symbol,b2_save=False):
key = f"split_{symbol}"
if persist.exists(key, "html"):
cached = persist.load(key, "html")
if cached is not False:
print(f"[{dt.now().strftime('%Y-%m-%d %H:%M:%S')}] Using cached split for {symbol}")
return cached
try:
df = split(symbol)
if df.empty:
return wrap_html(f"No splits for {symbol}
")
df_display = df.copy()
df_display.reset_index(inplace=True)
if b2_save:
b2.upload_file("eshanhf", f"intraday/{symbol}.csv", df)
html = wrap_html(make_table(df_display), title=f"{symbol} Splits")
persist.save(key, html, "html")
return html
except Exception as e:
print(f"[{dt.now().strftime('%Y-%m-%d %H:%M:%S')}] Error fetch_split: {e}")
return wrap_html(html_error(f"Split Error: {e}"))
# ================================================================
# EARNINGS
# ================================================================
def fetch_other(symbol,b2_save=False):
key = f"other_{symbol}"
if persist.exists(key, "html"):
cached = persist.load(key, "html")
if cached is not False:
print(f"[{dt.now().strftime('%Y-%m-%d %H:%M:%S')}] Using cached earnings for {symbol}")
return cached
try:
ticker = yf.Ticker(symbol + ".NS")
df = ticker.earnings
if df.empty:
return wrap_html(f"No earnings data for {symbol}
")
df_display = df.copy()
df_display.reset_index(inplace=True)
if b2_save:
b2.upload_file("eshanhf", f"intraday/{symbol}.csv", df)
html = wrap_html(make_table(df_display), title=f"{symbol} Earnings")
persist.save(key, html, "html")
return html
except Exception as e:
print(f"[{dt.now().strftime('%Y-%m-%d %H:%M:%S')}] Error fetch_other: {e}")
return wrap_html(html_error(f"Earnings Error: {e}"))