Spaces:
Sleeping
Sleeping
Update app/daily.py
Browse files- app/daily.py +38 -25
app/daily.py
CHANGED
|
@@ -14,6 +14,7 @@ from .common import wrap_html, format_large_number
|
|
| 14 |
# RAW DAILY FETCHER (from your stock.py)
|
| 15 |
# ===========================================================
|
| 16 |
def daily(symbol, date_end, date_start):
|
|
|
|
| 17 |
print(f"[{dt.now().strftime('%Y-%m-%d %H:%M:%S')}] yf called for {symbol}")
|
| 18 |
|
| 19 |
start = dt.strptime(date_start, "%d-%m-%Y").strftime("%Y-%m-%d")
|
|
@@ -24,11 +25,11 @@ def daily(symbol, date_end, date_start):
|
|
| 24 |
# Flatten MultiIndex columns if present
|
| 25 |
if isinstance(df.columns, pd.MultiIndex):
|
| 26 |
df.columns = df.columns.get_level_values(0)
|
| 27 |
-
|
| 28 |
return df
|
| 29 |
|
| 30 |
# ===========================================================
|
| 31 |
-
#
|
| 32 |
# ===========================================================
|
| 33 |
def detect_patterns(df):
|
| 34 |
patterns = []
|
|
@@ -81,15 +82,24 @@ def fetch_daily(symbol, date_end, date_start, b2_save=False):
|
|
| 81 |
try:
|
| 82 |
df = daily(symbol, date_end, date_start)
|
| 83 |
if df is None or df.empty:
|
| 84 |
-
return wrap_html(
|
| 85 |
|
| 86 |
-
# Reset index if
|
| 87 |
if not isinstance(df.index, pd.RangeIndex):
|
| 88 |
df.reset_index(inplace=True)
|
| 89 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 90 |
# Format date
|
| 91 |
df["Date"] = pd.to_datetime(df["Date"], errors='coerce')
|
| 92 |
-
df = df.dropna(subset=["Date"])
|
| 93 |
df["Date"] = df["Date"].dt.strftime("%d-%b-%Y")
|
| 94 |
|
| 95 |
if b2_save:
|
|
@@ -137,19 +147,21 @@ def fetch_daily(symbol, date_end, date_start, b2_save=False):
|
|
| 137 |
fig.add_trace(go.Scatter(x=df["Date"], y=df["UpperBB"], mode="lines", name="UpperBB", line=dict(dash="dot")), row=1, col=1)
|
| 138 |
fig.add_trace(go.Scatter(x=df["Date"], y=df["LowerBB"], mode="lines", name="LowerBB", line=dict(dash="dot")), row=1, col=1)
|
| 139 |
|
| 140 |
-
# Highlight patterns
|
| 141 |
if not patterns_df.empty:
|
| 142 |
for _, row in patterns_df.iterrows():
|
| 143 |
pattern_date = row["Date"]
|
| 144 |
-
|
| 145 |
-
|
| 146 |
-
|
| 147 |
-
|
| 148 |
-
|
| 149 |
-
|
| 150 |
-
|
| 151 |
-
|
| 152 |
-
|
|
|
|
|
|
|
| 153 |
|
| 154 |
# Volume
|
| 155 |
fig.add_trace(go.Bar(x=df["Date"], y=df["Volume"], name="Volume"), row=2, col=1)
|
|
@@ -159,18 +171,19 @@ def fetch_daily(symbol, date_end, date_start, b2_save=False):
|
|
| 159 |
fig.add_trace(go.Scatter(x=df["Date"], y=df["ATR"], mode="lines", name="ATR"), row=4, col=1)
|
| 160 |
|
| 161 |
fig.update_layout(height=1000, width=1200, title=f"{symbol} Daily Analysis Dashboard", xaxis_rangeslider_visible=False)
|
|
|
|
|
|
|
| 162 |
try:
|
| 163 |
-
chart_html = fig.to_html(full_html=False, include_plotlyjs=
|
| 164 |
except Exception as e:
|
| 165 |
-
chart_html = f"
|
| 166 |
|
| 167 |
-
# Tables
|
| 168 |
-
table_html =
|
| 169 |
-
data_table_html =
|
| 170 |
-
patterns_html =
|
| 171 |
-
|
| 172 |
-
|
| 173 |
-
)
|
| 174 |
|
| 175 |
full_html = chart_html + table_html + patterns_html + data_table_html
|
| 176 |
|
|
@@ -178,4 +191,4 @@ def fetch_daily(symbol, date_end, date_start, b2_save=False):
|
|
| 178 |
return full_html
|
| 179 |
|
| 180 |
except Exception as e:
|
| 181 |
-
return wrap_html(f"
|
|
|
|
| 14 |
# RAW DAILY FETCHER (from your stock.py)
|
| 15 |
# ===========================================================
|
| 16 |
def daily(symbol, date_end, date_start):
|
| 17 |
+
"""Fetch daily OHLCV from Yahoo Finance."""
|
| 18 |
print(f"[{dt.now().strftime('%Y-%m-%d %H:%M:%S')}] yf called for {symbol}")
|
| 19 |
|
| 20 |
start = dt.strptime(date_start, "%d-%m-%Y").strftime("%Y-%m-%d")
|
|
|
|
| 25 |
# Flatten MultiIndex columns if present
|
| 26 |
if isinstance(df.columns, pd.MultiIndex):
|
| 27 |
df.columns = df.columns.get_level_values(0)
|
| 28 |
+
|
| 29 |
return df
|
| 30 |
|
| 31 |
# ===========================================================
|
| 32 |
+
# PATTERN DETECTION (scalar-safe)
|
| 33 |
# ===========================================================
|
| 34 |
def detect_patterns(df):
|
| 35 |
patterns = []
|
|
|
|
| 82 |
try:
|
| 83 |
df = daily(symbol, date_end, date_start)
|
| 84 |
if df is None or df.empty:
|
| 85 |
+
return wrap_html('<div id="daily_wrapper"><h1>No daily data for {}</h1></div>'.format(symbol))
|
| 86 |
|
| 87 |
+
# Reset index if not simple RangeIndex
|
| 88 |
if not isinstance(df.index, pd.RangeIndex):
|
| 89 |
df.reset_index(inplace=True)
|
| 90 |
|
| 91 |
+
# Convert OHLCV to numeric safely
|
| 92 |
+
numeric_cols = ["Open","High","Low","Close","Adj Close","Volume"]
|
| 93 |
+
for col in numeric_cols:
|
| 94 |
+
if col in df.columns:
|
| 95 |
+
df[col] = pd.to_numeric(df[col], errors='coerce')
|
| 96 |
+
|
| 97 |
+
# Drop rows with missing essential data
|
| 98 |
+
df = df.dropna(subset=["Open","High","Low","Close","Volume"]).reset_index(drop=True)
|
| 99 |
+
|
| 100 |
# Format date
|
| 101 |
df["Date"] = pd.to_datetime(df["Date"], errors='coerce')
|
| 102 |
+
df = df.dropna(subset=["Date"]).reset_index(drop=True)
|
| 103 |
df["Date"] = df["Date"].dt.strftime("%d-%b-%Y")
|
| 104 |
|
| 105 |
if b2_save:
|
|
|
|
| 147 |
fig.add_trace(go.Scatter(x=df["Date"], y=df["UpperBB"], mode="lines", name="UpperBB", line=dict(dash="dot")), row=1, col=1)
|
| 148 |
fig.add_trace(go.Scatter(x=df["Date"], y=df["LowerBB"], mode="lines", name="LowerBB", line=dict(dash="dot")), row=1, col=1)
|
| 149 |
|
| 150 |
+
# Highlight patterns safely
|
| 151 |
if not patterns_df.empty:
|
| 152 |
for _, row in patterns_df.iterrows():
|
| 153 |
pattern_date = row["Date"]
|
| 154 |
+
matching = df[df["Date"]==pattern_date]
|
| 155 |
+
if not matching.empty:
|
| 156 |
+
high_value = matching["High"].values[0]
|
| 157 |
+
fig.add_trace(go.Scatter(
|
| 158 |
+
x=[pattern_date], y=[high_value*1.01],
|
| 159 |
+
mode="markers+text",
|
| 160 |
+
marker=dict(color="red", size=10, symbol="triangle-up"),
|
| 161 |
+
text=[row["Pattern"]],
|
| 162 |
+
textposition="top center",
|
| 163 |
+
showlegend=False
|
| 164 |
+
), row=1, col=1)
|
| 165 |
|
| 166 |
# Volume
|
| 167 |
fig.add_trace(go.Bar(x=df["Date"], y=df["Volume"], name="Volume"), row=2, col=1)
|
|
|
|
| 171 |
fig.add_trace(go.Scatter(x=df["Date"], y=df["ATR"], mode="lines", name="ATR"), row=4, col=1)
|
| 172 |
|
| 173 |
fig.update_layout(height=1000, width=1200, title=f"{symbol} Daily Analysis Dashboard", xaxis_rangeslider_visible=False)
|
| 174 |
+
|
| 175 |
+
chart_html = ""
|
| 176 |
try:
|
| 177 |
+
chart_html = f'<div id="chart_dashboard">{fig.to_html(full_html=False, include_plotlyjs="cdn")}</div>'
|
| 178 |
except Exception as e:
|
| 179 |
+
chart_html = f'<div id="chart_dashboard"><h2>Chart generation failed: {e}</h2></div>'
|
| 180 |
|
| 181 |
+
# Tables wrapped in divs for frontend safety
|
| 182 |
+
table_html = f'<div id="summary_stats"><h2>Summary Stats</h2>{summary.to_html(index=False, escape=False)}</div>'
|
| 183 |
+
data_table_html = f'<div id="ohlc_table"><h2>OHLC Table</h2>{df.to_html(index=False, escape=False)}</div>'
|
| 184 |
+
patterns_html = f'<div id="patterns_table"><h2>Detected Patterns</h2>'
|
| 185 |
+
patterns_html += patterns_df.to_html(index=False, escape=False) if not patterns_df.empty else "<p>No patterns detected.</p>"
|
| 186 |
+
patterns_html += "</div>"
|
|
|
|
| 187 |
|
| 188 |
full_html = chart_html + table_html + patterns_html + data_table_html
|
| 189 |
|
|
|
|
| 191 |
return full_html
|
| 192 |
|
| 193 |
except Exception as e:
|
| 194 |
+
return wrap_html(f'<div id="daily_wrapper"><h1>Error fetch_daily: {e}</h1><pre>{traceback.format_exc()}</pre></div>')
|