# 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)
| Date |
Open |
High |
Low |
Close |
Volume |
{rows}
Price & Volume
Moving Averages
"""
persist.save(key, html, "html")
return html
except Exception:
return f"{traceback.format_exc()}"