# daily.py import yfinance as yf import pandas as pd import matplotlib.pyplot as plt from datetime import datetime as dt import traceback import io import time from . import persist from . import backblaze as b2 # ============================================================ # CONFIG # ============================================================ IMAGE_FORMAT = "png" IMAGE_EXT = "png" DPI = 150 IMAGE_QUALITY = 85 # compression quality (PNG is lossless) # Public download base (DISPLAY ONLY, no change to backblaze.py) B2_PUBLIC_BASE = "https://f005.backblazeb2.com/file/eshanhf" # ⚠️ replace f005 if your Backblaze console shows different # ============================================================ # MAIN # ============================================================ def fetch_daily(symbol, date_end, date_start): key = f"daily_{symbol}" # -------------------------------------------------------- # Cache # -------------------------------------------------------- if persist.exists(key, "html"): cached = persist.load(key, "html") if cached: return cached try: # ---------------------------------------------------- # Date conversion # ---------------------------------------------------- start = dt.strptime(date_start, "%d-%m-%Y").strftime("%Y-%m-%d") end = dt.strptime(date_end, "%d-%m-%Y").strftime("%Y-%m-%d") # ---------------------------------------------------- # Fetch data # ---------------------------------------------------- df = yf.download(symbol + ".NS", start=start, end=end) if isinstance(df.columns, pd.MultiIndex): df.columns = df.columns.get_level_values(0) if df.empty: return "

No daily data found

" # ---------------------------------------------------- # Clean data # ---------------------------------------------------- df = df.reset_index() df["Date"] = pd.to_datetime(df["Date"], errors="coerce") df = df.dropna(subset=["Date"]) for c in ["Open", "High", "Low", "Close", "Volume"]: df[c] = pd.to_numeric(df[c], errors="coerce") df = df.dropna() df["DateStr"] = df["Date"].dt.strftime("%d-%b-%Y") # ---------------------------------------------------- # Indicators # ---------------------------------------------------- df["MA20"] = df["Close"].rolling(20).mean() df["MA50"] = df["Close"].rolling(50).mean() # ==================================================== # PRICE + VOLUME CHART # ==================================================== buf = io.BytesIO() plt.figure(figsize=(14, 6)) plt.plot(df["Date"], df["Close"], label="Close", linewidth=2) vol_scaled = df["Volume"] / df["Volume"].max() * df["Close"].max() plt.bar(df["Date"], vol_scaled, alpha=0.25, label="Volume") plt.title(f"{symbol} Price & Volume") plt.legend() plt.grid(True) plt.tight_layout() plt.savefig(buf, format=IMAGE_FORMAT, dpi=DPI, bbox_inches="tight") plt.close() buf.seek(0) price_key = f"daily/{symbol}_price_volume.{IMAGE_EXT}" b2.upload_image_compressed( "eshanhf", price_key, buf.getvalue(), quality=IMAGE_QUALITY ) # ==================================================== # MOVING AVERAGE CHART # ==================================================== buf = io.BytesIO() plt.figure(figsize=(14, 6)) plt.plot(df["Date"], df["Close"], label="Close", linewidth=2) plt.plot(df["Date"], df["MA20"], label="MA20") plt.plot(df["Date"], df["MA50"], label="MA50") plt.title(f"{symbol} Moving Averages") plt.legend() plt.grid(True) plt.tight_layout() plt.savefig(buf, format=IMAGE_FORMAT, dpi=DPI, bbox_inches="tight") plt.close() buf.seek(0) ma_key = f"daily/{symbol}_ma.{IMAGE_EXT}" b2.upload_image_compressed( "eshanhf", ma_key, buf.getvalue(), quality=IMAGE_QUALITY ) # ---------------------------------------------------- # Cache-busting timestamp # ---------------------------------------------------- ts = int(time.time()) price_url = f"{B2_PUBLIC_BASE}/{price_key}?v={ts}" ma_url = f"{B2_PUBLIC_BASE}/{ma_key}?v={ts}" # ==================================================== # TABLE (Last 100 days) # ==================================================== rows = "" for r in df.tail(100).itertuples(): rows += f""" {r.DateStr} {r.Open:.2f} {r.High:.2f} {r.Low:.2f} {r.Close:.2f} {int(r.Volume)} """ # ==================================================== # FINAL HTML (IMAGE WAIT + RETRY) # ==================================================== html = f"""

{symbol} – Daily Analysis

Price Table (Last 100 Days)

{rows}
Date Open High Low Close Volume

Price & Volume

Moving Averages

""" persist.save(key, html, "html") return html except Exception: return f"
{traceback.format_exc()}
"