Spaces:
Sleeping
Sleeping
Update app/daily.py
Browse files- app/daily.py +11 -74
app/daily.py
CHANGED
|
@@ -2,16 +2,13 @@
|
|
| 2 |
import yfinance as yf
|
| 3 |
import pandas as pd
|
| 4 |
from datetime import datetime as dt
|
| 5 |
-
from plotly import graph_objs as go
|
| 6 |
-
from plotly.subplots import make_subplots
|
| 7 |
import traceback
|
| 8 |
|
| 9 |
from . import persist
|
| 10 |
-
from . import
|
| 11 |
-
from .common import wrap_html, format_large_number
|
| 12 |
|
| 13 |
# ===========================================================
|
| 14 |
-
# RAW DAILY FETCHER
|
| 15 |
# ===========================================================
|
| 16 |
def daily(symbol, date_end, date_start):
|
| 17 |
"""Fetch daily OHLCV from Yahoo Finance."""
|
|
@@ -20,7 +17,7 @@ def daily(symbol, date_end, date_start):
|
|
| 20 |
start = dt.strptime(date_start, "%d-%m-%Y").strftime("%Y-%m-%d")
|
| 21 |
end = dt.strptime(date_end, "%d-%m-%Y").strftime("%Y-%m-%d")
|
| 22 |
|
| 23 |
-
df = yf.download(symbol + ".NS", start=start, end=end)
|
| 24 |
|
| 25 |
# Flatten MultiIndex columns if present
|
| 26 |
if isinstance(df.columns, pd.MultiIndex):
|
|
@@ -29,9 +26,9 @@ def daily(symbol, date_end, date_start):
|
|
| 29 |
return df
|
| 30 |
|
| 31 |
# ===========================================================
|
| 32 |
-
#
|
| 33 |
# ===========================================================
|
| 34 |
-
def fetch_daily(symbol, date_end, date_start
|
| 35 |
key = f"daily_{symbol}"
|
| 36 |
if persist.exists(key, "html"):
|
| 37 |
cached = persist.load(key, "html")
|
|
@@ -48,7 +45,7 @@ def fetch_daily(symbol, date_end, date_start, b2_save=False):
|
|
| 48 |
if not isinstance(df.index, pd.RangeIndex):
|
| 49 |
df.reset_index(inplace=True)
|
| 50 |
|
| 51 |
-
# Convert
|
| 52 |
numeric_cols = ["Open","High","Low","Close","Adj Close","Volume"]
|
| 53 |
for col in numeric_cols:
|
| 54 |
if col in df.columns:
|
|
@@ -62,72 +59,12 @@ def fetch_daily(symbol, date_end, date_start, b2_save=False):
|
|
| 62 |
df = df.dropna(subset=["Date"]).reset_index(drop=True)
|
| 63 |
df["Date"] = df["Date"].dt.strftime("%d-%b-%Y")
|
| 64 |
|
| 65 |
-
|
| 66 |
-
|
| 67 |
|
| 68 |
-
#
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
df["SMA50"] = df["Close"].rolling(50).mean()
|
| 72 |
-
df["EMA20"] = df["Close"].ewm(span=20, adjust=False).mean()
|
| 73 |
-
df["EMA50"] = df["Close"].ewm(span=50, adjust=False).mean()
|
| 74 |
-
df["UpperBB"] = df["Close"].rolling(20).mean() + 2*df["Close"].rolling(20).std()
|
| 75 |
-
df["LowerBB"] = df["Close"].rolling(20).mean() - 2*df["Close"].rolling(20).std()
|
| 76 |
-
df["ATR"] = df["High"].combine(df["Low"], lambda h,l: h-l).rolling(14).mean()
|
| 77 |
-
|
| 78 |
-
# Summary stats
|
| 79 |
-
summary = pd.DataFrame({
|
| 80 |
-
"Metric": ["Start Date","End Date","Min Price","Max Price","Mean Price","Total Volume","Avg Daily Return %","Volatility ATR"],
|
| 81 |
-
"Value": [
|
| 82 |
-
df["Date"].iloc[0],
|
| 83 |
-
df["Date"].iloc[-1],
|
| 84 |
-
format_large_number(df["Close"].min()),
|
| 85 |
-
format_large_number(df["Close"].max()),
|
| 86 |
-
format_large_number(df["Close"].mean()),
|
| 87 |
-
format_large_number(df["Volume"].sum()),
|
| 88 |
-
f"{df['Daily Return %'].mean():.2f}%",
|
| 89 |
-
f"{df['ATR'].mean():.2f}"
|
| 90 |
-
]
|
| 91 |
-
})
|
| 92 |
-
|
| 93 |
-
# Plotly dashboard
|
| 94 |
-
fig = make_subplots(rows=4, cols=1, shared_xaxes=True,
|
| 95 |
-
vertical_spacing=0.05,
|
| 96 |
-
row_heights=[0.4,0.2,0.2,0.2],
|
| 97 |
-
specs=[[{}],[{}],[{}],[{}]])
|
| 98 |
-
|
| 99 |
-
# Candlestick + moving averages + Bollinger
|
| 100 |
-
fig.add_trace(go.Candlestick(x=df["Date"], open=df["Open"], high=df["High"], low=df["Low"], close=df["Close"], name="OHLC"), row=1, col=1)
|
| 101 |
-
fig.add_trace(go.Scatter(x=df["Date"], y=df["SMA20"], mode="lines", name="SMA20"), row=1, col=1)
|
| 102 |
-
fig.add_trace(go.Scatter(x=df["Date"], y=df["SMA50"], mode="lines", name="SMA50"), row=1, col=1)
|
| 103 |
-
fig.add_trace(go.Scatter(x=df["Date"], y=df["EMA20"], mode="lines", name="EMA20"), row=1, col=1)
|
| 104 |
-
fig.add_trace(go.Scatter(x=df["Date"], y=df["EMA50"], mode="lines", name="EMA50"), row=1, col=1)
|
| 105 |
-
fig.add_trace(go.Scatter(x=df["Date"], y=df["UpperBB"], mode="lines", name="UpperBB", line=dict(dash="dot")), row=1, col=1)
|
| 106 |
-
fig.add_trace(go.Scatter(x=df["Date"], y=df["LowerBB"], mode="lines", name="LowerBB", line=dict(dash="dot")), row=1, col=1)
|
| 107 |
-
|
| 108 |
-
# Volume
|
| 109 |
-
fig.add_trace(go.Bar(x=df["Date"], y=df["Volume"], name="Volume"), row=2, col=1)
|
| 110 |
-
# Daily Return %
|
| 111 |
-
fig.add_trace(go.Scatter(x=df["Date"], y=df["Daily Return %"], mode="lines+markers", name="Daily Return %"), row=3, col=1)
|
| 112 |
-
# ATR
|
| 113 |
-
fig.add_trace(go.Scatter(x=df["Date"], y=df["ATR"], mode="lines", name="ATR"), row=4, col=1)
|
| 114 |
-
|
| 115 |
-
fig.update_layout(height=1000, width=1200, title=f"{symbol} Daily Analysis Dashboard", xaxis_rangeslider_visible=False)
|
| 116 |
-
|
| 117 |
-
chart_html = ""
|
| 118 |
-
try:
|
| 119 |
-
chart_html = f'<div id="chart_dashboard">{fig.to_html(full_html=False, include_plotlyjs="cdn")}</div>'
|
| 120 |
-
except Exception as e:
|
| 121 |
-
chart_html = f'<div id="chart_dashboard"><h2>Chart generation failed: {e}</h2></div>'
|
| 122 |
-
|
| 123 |
-
# Tables wrapped in divs
|
| 124 |
-
table_html = f'<div id="summary_stats"><h2>Summary Stats</h2>{summary.to_html(index=False, escape=False)}</div>'
|
| 125 |
-
data_table_html = f'<div id="ohlc_table"><h2>OHLC Table</h2>{df.to_html(index=False, escape=False)}</div>'
|
| 126 |
-
|
| 127 |
-
full_html = chart_html + table_html + data_table_html
|
| 128 |
-
|
| 129 |
-
persist.save(key, full_html, "html")
|
| 130 |
-
return full_html
|
| 131 |
|
| 132 |
except Exception as e:
|
| 133 |
return wrap_html(f'<div id="daily_wrapper"><h1>Error fetch_daily: {e}</h1><pre>{traceback.format_exc()}</pre></div>')
|
|
|
|
| 2 |
import yfinance as yf
|
| 3 |
import pandas as pd
|
| 4 |
from datetime import datetime as dt
|
|
|
|
|
|
|
| 5 |
import traceback
|
| 6 |
|
| 7 |
from . import persist
|
| 8 |
+
from .common import wrap_html
|
|
|
|
| 9 |
|
| 10 |
# ===========================================================
|
| 11 |
+
# RAW DAILY FETCHER
|
| 12 |
# ===========================================================
|
| 13 |
def daily(symbol, date_end, date_start):
|
| 14 |
"""Fetch daily OHLCV from Yahoo Finance."""
|
|
|
|
| 17 |
start = dt.strptime(date_start, "%d-%m-%Y").strftime("%Y-%m-%d")
|
| 18 |
end = dt.strptime(date_end, "%d-%m-%Y").strftime("%Y-%m-%d")
|
| 19 |
|
| 20 |
+
df = yf.download(symbol + ".NS", start=start, end=end)
|
| 21 |
|
| 22 |
# Flatten MultiIndex columns if present
|
| 23 |
if isinstance(df.columns, pd.MultiIndex):
|
|
|
|
| 26 |
return df
|
| 27 |
|
| 28 |
# ===========================================================
|
| 29 |
+
# FETCH DAILY HTML TABLE
|
| 30 |
# ===========================================================
|
| 31 |
+
def fetch_daily(symbol, date_end, date_start):
|
| 32 |
key = f"daily_{symbol}"
|
| 33 |
if persist.exists(key, "html"):
|
| 34 |
cached = persist.load(key, "html")
|
|
|
|
| 45 |
if not isinstance(df.index, pd.RangeIndex):
|
| 46 |
df.reset_index(inplace=True)
|
| 47 |
|
| 48 |
+
# Convert numeric columns safely
|
| 49 |
numeric_cols = ["Open","High","Low","Close","Adj Close","Volume"]
|
| 50 |
for col in numeric_cols:
|
| 51 |
if col in df.columns:
|
|
|
|
| 59 |
df = df.dropna(subset=["Date"]).reset_index(drop=True)
|
| 60 |
df["Date"] = df["Date"].dt.strftime("%d-%b-%Y")
|
| 61 |
|
| 62 |
+
# Build HTML table
|
| 63 |
+
html_table = f'<div id="daily_table"><h2>{symbol} Daily Data</h2>{df.to_html(index=False, escape=False)}</div>'
|
| 64 |
|
| 65 |
+
# Save to cache
|
| 66 |
+
persist.save(key, html_table, "html")
|
| 67 |
+
return html_table
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 68 |
|
| 69 |
except Exception as e:
|
| 70 |
return wrap_html(f'<div id="daily_wrapper"><h1>Error fetch_daily: {e}</h1><pre>{traceback.format_exc()}</pre></div>')
|