from nsepython import * import pandas as pd import re from datetime import datetime as dt # persist helpers (ALREADY EXIST IN YOUR PROJECT) from persist import exists, load, save def build_preopen_html(key="NIFTY"): """ Build full Pre-Open HTML with daily cache. If cached HTML exists for today → return it. Else → fetch, rebuild, save, return. """ # ================= CACHE ================= today = dt.now().strftime("%Y-%m-%d") cache_key = f"preopen_html_{key}" if exists(cache_key): cached = load(cache_key) if isinstance(cached, dict) and cached.get("date") == today: return cached.get("html") # ================= FETCH DATA ================= p = nsefetch(f"https://www.nseindia.com/api/market-data-pre-open?key={key}") data_df = df_from_data(p.pop("data")) rem_df = df_from_data([p]) main_df = data_df.iloc[[0]] if not data_df.empty else pd.DataFrame() const_df = data_df.iloc[1:] if len(data_df) > 1 else pd.DataFrame() # ================= REMOVE PATTERN COLUMNS ================= pattern_remove = re.compile(r"^(price_|buyQty_|sellQty_|iep_)\d+$") def remove_pattern_cols(df): if df is None or df.empty: return df return df[[c for c in df.columns if not pattern_remove.match(c)]] main_df = remove_pattern_cols(main_df) const_df = remove_pattern_cols(const_df) rem_df = remove_pattern_cols(rem_df) # ================= TABLE COLOR HELPER ================= def df_to_html_color(df, metric_col=None): if df is None or df.empty: return "No data" df_html = df.copy() top3_up, top3_down = [], [] if metric_col and metric_col in df_html.columns: if pd.api.types.is_numeric_dtype(df_html[metric_col]): col_numeric = df_html[metric_col].dropna() top3_up = col_numeric.nlargest(3).index.tolist() top3_down = col_numeric.nsmallest(3).index.tolist() for idx, row in df_html.iterrows(): for col in df_html.columns: val = row[col] style = "" if isinstance(val, (int, float)): val_fmt = f"{val:.2f}" if val > 0: style = "numeric-positive" elif val < 0: style = "numeric-negative" if col == metric_col: if idx in top3_up: style += " top-up" elif idx in top3_down: style += " top-down" df_html.at[idx, col] = f'{val_fmt}' else: df_html.at[idx, col] = str(val) return df_html.to_html(index=False, escape=False, classes="compact-table") # ================= MINI CARDS ================= def build_info_cards(rem_df, main_df): combined = pd.concat([rem_df, main_df], axis=1) combined = combined.loc[:, ~combined.columns.duplicated()] combined = remove_pattern_cols(combined) cards = '
' for col in combined.columns: val = combined.at[0, col] if not combined.empty else "" cards += f"""
{col}
{val}
""" cards += '
' return cards info_cards_html = build_info_cards(rem_df, main_df) # ================= CONSTITUENTS TABLE ================= cons_html = df_to_html_color(const_df) # ================= METRIC TABLES ================= metric_cols_allowed = [ "pChange", "totalTurnover", "marketCap", "totalTradedVolume" ] metric_tables = "" for col in metric_cols_allowed: if col in const_df.columns and pd.api.types.is_numeric_dtype(const_df[col]): df_metric = const_df.copy() df_metric[col] = pd.to_numeric(df_metric[col], errors="coerce") df_metric = df_metric.sort_values(col, ascending=False) show_cols = ["symbol", col] if "symbol" in df_metric.columns else [col] metric_tables += f"""
{col}
{df_to_html_color(df_metric[show_cols], metric_col=col)}
""" # ================= FINAL HTML ================= html = f"""

Pre-Open Market — {key}

Info

{info_cards_html}

Constituents

{cons_html}

Key Metrics

{metric_tables}
""" # ================= SAVE CACHE ================= save(cache_key, { "date": today, "html": html }) return html