from . import nsepythonmodified as ns import pandas as pd import re from datetime import datetime as dt # persist helpers (HF only) from .persist import exists, load, save def build_preopen_html(key): """ Build full Pre-Open HTML - Daily TTL (via persist.py) - HTML only cache """ # ================= CACHE (TTL via persist) ================= cache_name = f"DAILY_PREOPEN_{key.upper()}" if exists(cache_name, "html"): cached_html = load(cache_name, "html") if isinstance(cached_html, str): return cached_html # ================= FETCH DATA ================= p = ns.nse_preopen(key) data_df = p["data"] rem_df = p["rem"] 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() top_up, top_down = [], [] if metric_col and metric_col in df_html.columns: col_num = pd.to_numeric(df_html[metric_col], errors="coerce").dropna() top_up = col_num.nlargest(3).index.tolist() top_down = col_num.nsmallest(3).index.tolist() for idx, row in df_html.iterrows(): for col in df_html.columns: val = row[col] cls = "" if isinstance(val, (int, float)): val_fmt = f"{val:.2f}" if val > 0: cls = "numeric-positive" elif val < 0: cls = "numeric-negative" if metric_col and col == metric_col: if idx in top_up: cls += " top-up" elif idx in top_down: cls += " 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 INFO 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) html = '
' for col in combined.columns: val = combined.at[0, col] if not combined.empty else "" html += f"""
{col}
{val}
""" html += '
' return html 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: df_m = const_df.copy() df_m[col] = pd.to_numeric(df_m[col], errors="coerce") df_m = df_m.sort_values(col, ascending=False) show_cols = ["symbol", col] if "symbol" in df_m.columns else [col] metric_tables += f"""
{col}
{df_to_html_color(df_m[show_cols], metric_col=col)}
""" # ================= FINAL HTML ================= html_out = f"""

Pre-Open Market — {key}

Info

{info_cards_html}

Constituents

{cons_html}

Key Metrics

{metric_tables}
""" # ================= SAVE (HTML ONLY) ================= save(cache_name, html_out, "html") return html_out