eshan6704 commited on
Commit
8e82e4f
·
verified ·
1 Parent(s): cac815d

Update preopen_html.py

Browse files
Files changed (1) hide show
  1. preopen_html.py +112 -66
preopen_html.py CHANGED
@@ -1,94 +1,134 @@
1
  from nsepython import *
2
  import pandas as pd
3
  import re
 
 
 
 
 
4
 
5
  def build_preopen_html(key="NIFTY"):
6
- # Fetch pre-open data
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
  p = nsefetch(f"https://www.nseindia.com/api/market-data-pre-open?key={key}")
 
8
  data_df = df_from_data(p.pop("data"))
9
  rem_df = df_from_data([p])
10
-
11
- main_df = data_df.iloc[[0]] if not data_df.empty else pd.DataFrame()
12
  const_df = data_df.iloc[1:] if len(data_df) > 1 else pd.DataFrame()
13
-
14
- # ================= REMOVE *_x AND SPECIFIC PATTERNS =================
15
  pattern_remove = re.compile(r"^(price_|buyQty_|sellQty_|iep_)\d+$")
16
-
17
  def remove_pattern_cols(df):
 
 
18
  return df[[c for c in df.columns if not pattern_remove.match(c)]]
19
-
20
- main_df = remove_pattern_cols(main_df)
21
  const_df = remove_pattern_cols(const_df)
22
- rem_df = remove_pattern_cols(rem_df)
23
 
24
- # ================= HELPER FUNCTION =================
25
  def df_to_html_color(df, metric_col=None):
 
 
 
26
  df_html = df.copy()
27
  top3_up, top3_down = [], []
28
- if metric_col and metric_col in df_html.columns and pd.api.types.is_numeric_dtype(df_html[metric_col]):
29
- col_numeric = df_html[metric_col].dropna()
30
- top3_up = col_numeric.nlargest(3).index.tolist()
31
- top3_down = col_numeric.nsmallest(3).index.tolist()
 
 
32
 
33
  for idx, row in df_html.iterrows():
34
  for col in df_html.columns:
35
  val = row[col]
36
  style = ""
 
37
  if isinstance(val, (int, float)):
38
  val_fmt = f"{val:.2f}"
39
  if val > 0:
40
  style = "numeric-positive"
41
  elif val < 0:
42
  style = "numeric-negative"
43
- if metric_col == col:
 
44
  if idx in top3_up:
45
  style += " top-up"
46
  elif idx in top3_down:
47
  style += " top-down"
 
48
  df_html.at[idx, col] = f'<span class="{style.strip()}">{val_fmt}</span>'
49
  else:
50
  df_html.at[idx, col] = str(val)
 
51
  return df_html.to_html(index=False, escape=False, classes="compact-table")
52
 
53
- # ================= MINI-CARDS =================
54
- def merge_info_main_cards(rem_df, main_df):
55
  combined = pd.concat([rem_df, main_df], axis=1)
56
  combined = combined.loc[:, ~combined.columns.duplicated()]
57
- # Remove pattern columns
58
- combined = combined[[c for c in combined.columns if not pattern_remove.match(c)]]
59
- cards_html = '<div class="mini-card-container">'
60
  for col in combined.columns:
61
  val = combined.at[0, col] if not combined.empty else ""
62
- cards_html += f'''
63
  <div class="mini-card">
64
  <div class="card-key">{col}</div>
65
  <div class="card-val">{val}</div>
66
  </div>
67
- '''
68
- cards_html += '</div>'
69
- return cards_html
70
 
71
- info_cards_html = merge_info_main_cards(rem_df, main_df)
72
 
73
- # ================= Constituents table =================
74
- cons_html = df_to_html_color(const_df) if not const_df.empty else "<i>No pre-open constituents</i>"
75
 
76
- # ================= Metric tables (restricted to selected columns) =================
77
- metric_cols_allowed = ["pChange", "totalTurnover", "marketCap", "totalTradedVolume"]
78
- metric_cols = [c for c in metric_cols_allowed if c in const_df.columns and pd.api.types.is_numeric_dtype(const_df[c])] if not const_df.empty else []
 
 
 
 
79
 
80
  metric_tables = ""
81
- for col in metric_cols:
82
- df_const = const_df.copy()
83
- df_const[col] = pd.to_numeric(df_const[col], errors="ignore")
84
- df_const = df_const.sort_values(col, ascending=False)
85
- df_html = df_to_html_color(df_const[['symbol', col]] if 'symbol' in df_const.columns else df_const[[col]], metric_col=col)
86
- metric_tables += f"""
87
- <div class="small-table">
88
- <div class="st-title">{col}</div>
89
- <div class="st-body">{df_html}</div>
90
- </div>
91
- """
 
 
 
 
92
 
93
  # ================= FINAL HTML =================
94
  html = f"""
@@ -97,45 +137,51 @@ def build_preopen_html(key="NIFTY"):
97
  <head>
98
  <meta charset="UTF-8">
99
  <style>
100
- body {{ font-family: Arial; margin: 12px; background: #f5f5f5; color: #222; font-size: 14px; }}
101
- h2, h3 {{ margin: 12px 0 6px 0; font-weight: 600; }}
102
- table {{ border-collapse: collapse; width: 100%; table-layout: auto; }}
103
- th, td {{ border: 1px solid #bbb; padding: 5px 8px; text-align: left; font-size: 13px; }}
104
- th {{ background: #333; color: white; font-weight: 600; }}
 
105
  .compact-table td.numeric-positive {{ color: green; font-weight: bold; }}
106
  .compact-table td.numeric-negative {{ color: red; font-weight: bold; }}
107
- .compact-table td.top-up {{ background: #a8f0a5; }}
108
- .compact-table td.top-down {{ background: #f0a8a8; }}
109
- .small-table {{ background: white; border-radius: 6px; padding: 8px; box-shadow: 0px 1px 4px rgba(0,0,0,0.15); border: 1px solid #ddd; overflow-y: auto; }}
110
- .st-title {{ font-size: 14px; text-align: center; margin-bottom: 6px; font-weight: bold; background: #222; color: white; padding: 5px 0; border-radius: 4px; }}
111
- .st-body {{ max-height: 300px; overflow-y: auto; font-size: 12px; }}
112
- .grid {{ display: grid; grid-template-columns: repeat(5, 1fr); gap: 12px; margin-top: 12px; }}
 
 
113
  .mini-card-container {{ display: flex; flex-wrap: wrap; gap: 10px; }}
114
- .mini-card {{ background: #fff; padding: 8px 10px; border-radius: 6px; box-shadow: 0 1px 3px rgba(0,0,0,0.12); min-width: 120px; font-size: 13px; }}
115
- .card-key {{ font-weight: bold; color: #333; margin-bottom: 2px; }}
116
- .card-val {{ color: #222; }}
117
  </style>
118
  </head>
 
119
  <body>
120
 
121
- <h2>Pre-Open Data: {key}</h2>
122
 
123
- <div class="compact-section">
124
- <h3>Info + Main Data</h3>
125
- {info_cards_html}
126
- </div>
127
 
128
- <div class="compact-section">
129
- <h3>Pre-Open Constituents</h3>
130
- {cons_html}
131
- </div>
132
 
133
- <h3>Metric Tables (selected numeric)</h3>
134
  <div class="grid">
135
- {metric_tables}
136
  </div>
137
 
138
  </body>
139
  </html>
140
  """
 
 
 
 
 
 
 
141
  return html
 
1
  from nsepython import *
2
  import pandas as pd
3
  import re
4
+ from datetime import datetime as dt
5
+
6
+ # persist helpers (ALREADY EXIST IN YOUR PROJECT)
7
+ from persist import exists, load, save
8
+
9
 
10
  def build_preopen_html(key="NIFTY"):
11
+ """
12
+ Build full Pre-Open HTML with daily cache.
13
+ If cached HTML exists for today → return it.
14
+ Else → fetch, rebuild, save, return.
15
+ """
16
+
17
+ # ================= CACHE =================
18
+ today = dt.now().strftime("%Y-%m-%d")
19
+ cache_key = f"preopen_html_{key}"
20
+
21
+ if exists(cache_key):
22
+ cached = load(cache_key)
23
+ if isinstance(cached, dict) and cached.get("date") == today:
24
+ return cached.get("html")
25
+
26
+ # ================= FETCH DATA =================
27
  p = nsefetch(f"https://www.nseindia.com/api/market-data-pre-open?key={key}")
28
+
29
  data_df = df_from_data(p.pop("data"))
30
  rem_df = df_from_data([p])
31
+
32
+ main_df = data_df.iloc[[0]] if not data_df.empty else pd.DataFrame()
33
  const_df = data_df.iloc[1:] if len(data_df) > 1 else pd.DataFrame()
34
+
35
+ # ================= REMOVE PATTERN COLUMNS =================
36
  pattern_remove = re.compile(r"^(price_|buyQty_|sellQty_|iep_)\d+$")
37
+
38
  def remove_pattern_cols(df):
39
+ if df is None or df.empty:
40
+ return df
41
  return df[[c for c in df.columns if not pattern_remove.match(c)]]
42
+
43
+ main_df = remove_pattern_cols(main_df)
44
  const_df = remove_pattern_cols(const_df)
45
+ rem_df = remove_pattern_cols(rem_df)
46
 
47
+ # ================= TABLE COLOR HELPER =================
48
  def df_to_html_color(df, metric_col=None):
49
+ if df is None or df.empty:
50
+ return "<i>No data</i>"
51
+
52
  df_html = df.copy()
53
  top3_up, top3_down = [], []
54
+
55
+ if metric_col and metric_col in df_html.columns:
56
+ if pd.api.types.is_numeric_dtype(df_html[metric_col]):
57
+ col_numeric = df_html[metric_col].dropna()
58
+ top3_up = col_numeric.nlargest(3).index.tolist()
59
+ top3_down = col_numeric.nsmallest(3).index.tolist()
60
 
61
  for idx, row in df_html.iterrows():
62
  for col in df_html.columns:
63
  val = row[col]
64
  style = ""
65
+
66
  if isinstance(val, (int, float)):
67
  val_fmt = f"{val:.2f}"
68
  if val > 0:
69
  style = "numeric-positive"
70
  elif val < 0:
71
  style = "numeric-negative"
72
+
73
+ if col == metric_col:
74
  if idx in top3_up:
75
  style += " top-up"
76
  elif idx in top3_down:
77
  style += " top-down"
78
+
79
  df_html.at[idx, col] = f'<span class="{style.strip()}">{val_fmt}</span>'
80
  else:
81
  df_html.at[idx, col] = str(val)
82
+
83
  return df_html.to_html(index=False, escape=False, classes="compact-table")
84
 
85
+ # ================= MINI CARDS =================
86
+ def build_info_cards(rem_df, main_df):
87
  combined = pd.concat([rem_df, main_df], axis=1)
88
  combined = combined.loc[:, ~combined.columns.duplicated()]
89
+ combined = remove_pattern_cols(combined)
90
+
91
+ cards = '<div class="mini-card-container">'
92
  for col in combined.columns:
93
  val = combined.at[0, col] if not combined.empty else ""
94
+ cards += f"""
95
  <div class="mini-card">
96
  <div class="card-key">{col}</div>
97
  <div class="card-val">{val}</div>
98
  </div>
99
+ """
100
+ cards += '</div>'
101
+ return cards
102
 
103
+ info_cards_html = build_info_cards(rem_df, main_df)
104
 
105
+ # ================= CONSTITUENTS TABLE =================
106
+ cons_html = df_to_html_color(const_df)
107
 
108
+ # ================= METRIC TABLES =================
109
+ metric_cols_allowed = [
110
+ "pChange",
111
+ "totalTurnover",
112
+ "marketCap",
113
+ "totalTradedVolume"
114
+ ]
115
 
116
  metric_tables = ""
117
+ for col in metric_cols_allowed:
118
+ if col in const_df.columns and pd.api.types.is_numeric_dtype(const_df[col]):
119
+ df_metric = const_df.copy()
120
+ df_metric[col] = pd.to_numeric(df_metric[col], errors="coerce")
121
+ df_metric = df_metric.sort_values(col, ascending=False)
122
+
123
+ show_cols = ["symbol", col] if "symbol" in df_metric.columns else [col]
124
+ metric_tables += f"""
125
+ <div class="small-table">
126
+ <div class="st-title">{col}</div>
127
+ <div class="st-body">
128
+ {df_to_html_color(df_metric[show_cols], metric_col=col)}
129
+ </div>
130
+ </div>
131
+ """
132
 
133
  # ================= FINAL HTML =================
134
  html = f"""
 
137
  <head>
138
  <meta charset="UTF-8">
139
  <style>
140
+ body {{ font-family: Arial; margin: 12px; background: #f5f5f5; font-size: 14px; }}
141
+ h2, h3 {{ margin: 10px 0; }}
142
+ table {{ border-collapse: collapse; width: 100%; }}
143
+ th, td {{ border: 1px solid #bbb; padding: 6px; font-size: 13px; }}
144
+ th {{ background: #333; color: #fff; }}
145
+
146
  .compact-table td.numeric-positive {{ color: green; font-weight: bold; }}
147
  .compact-table td.numeric-negative {{ color: red; font-weight: bold; }}
148
+ .compact-table td.top-up {{ background: #b6f2b6; }}
149
+ .compact-table td.top-down {{ background: #f2b6b6; }}
150
+
151
+ .grid {{ display: grid; grid-template-columns: repeat(5, 1fr); gap: 12px; }}
152
+ .small-table {{ background: #fff; padding: 8px; border-radius: 6px; border: 1px solid #ddd; }}
153
+ .st-title {{ text-align: center; font-weight: bold; background: #222; color: #fff; padding: 6px; border-radius: 4px; }}
154
+ .st-body {{ max-height: 300px; overflow-y: auto; }}
155
+
156
  .mini-card-container {{ display: flex; flex-wrap: wrap; gap: 10px; }}
157
+ .mini-card {{ background: #fff; padding: 8px 10px; border-radius: 6px; border: 1px solid #ddd; min-width: 120px; }}
158
+ .card-key {{ font-weight: bold; }}
 
159
  </style>
160
  </head>
161
+
162
  <body>
163
 
164
+ <h2>Pre-Open Market {key}</h2>
165
 
166
+ <h3>Info</h3>
167
+ {info_cards_html}
 
 
168
 
169
+ <h3>Constituents</h3>
170
+ {cons_html}
 
 
171
 
172
+ <h3>Key Metrics</h3>
173
  <div class="grid">
174
+ {metric_tables}
175
  </div>
176
 
177
  </body>
178
  </html>
179
  """
180
+
181
+ # ================= SAVE CACHE =================
182
+ save(cache_key, {
183
+ "date": today,
184
+ "html": html
185
+ })
186
+
187
  return html