Add web dev dashboard with real-time HK weather + model comparison

- Flask web server with interactive charts (Chart.js)
- Temperature, rain probability, wind speed charts with HKO vs Open-Meteo comparison
- Current conditions card with typhoon signal indicator
- Kelly criterion sizing simulator panel
- Trading signals panel with model-implied probabilities
- Raw forecast data JSON viewer
- Github-dark theme with responsive card layout
- Fixed Open-Meteo SDK compatibility and numpy bool serialization

Run: python web_dashboard.py  # http://localhost:5000
This commit is contained in:
ramseshk
2026-08-10 17:11:49 +08:00
parent c93af97059
commit e59076ad6a
2 changed files with 655 additions and 8 deletions
+11 -8
View File
@@ -149,9 +149,11 @@ class OpenMeteoClient:
daily_df.index = daily_df.index.tz_convert("Asia/Hong_Kong")
daily_df.attrs["model"] = self.model
daily_df.attrs["hourly"] = hourly_df
daily_df.attrs["fetch_time"] = datetime.now()
# Store hourly separately to avoid pandas attrs bug with DataFrames
self._last_hourly = hourly_df
return daily_df
def get_current_conditions(self) -> dict:
@@ -196,12 +198,13 @@ class OpenMeteoClient:
def get_precipitation_probability(self, hours_ahead: int = 24) -> float:
"""Get precipitation probability for next N hours."""
df = self.get_forecast(lead_days=2)
if df is not None and hasattr(df, 'attrs') and 'hourly' in df.attrs:
hourly = df.attrs['hourly']
now = pd.Timestamp.now(tz="Asia/Hong_Kong")
future = hourly[hourly.index <= now + pd.Timedelta(hours=hours_ahead)]
if 'precipitation_probability' in future.columns:
return float(future['precipitation_probability'].max())
if df is not None:
hourly = getattr(self, '_last_hourly', pd.DataFrame())
if not hourly.empty:
now = pd.Timestamp.now(tz="Asia/Hong_Kong")
future = hourly[hourly.index <= now + pd.Timedelta(hours=hours_ahead)]
if 'precipitation_probability' in future.columns:
return float(future['precipitation_probability'].max())
return 0.0
def get_scoring_window_summary(self, target_date: str) -> dict:
@@ -220,7 +223,7 @@ class OpenMeteoClient:
return {}
row = df.loc[target]
hourly = df.attrs.get("hourly", pd.DataFrame())
hourly = getattr(self, '_last_hourly', pd.DataFrame())
if not hourly.empty:
day_hourly = hourly[