|
|
import pandas as pd |
|
|
import nsepython as nse |
|
|
import persist |
|
|
from datetime import datetime as dt |
|
|
|
|
|
|
|
|
def build_bhavcopy_html(date_str): |
|
|
key = f"bhavcopy_{date_str}" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if persist.exists(key, "html"): |
|
|
cached = persist.load(key, "html") |
|
|
if cached is not False: |
|
|
print( |
|
|
f"[{dt.now().strftime('%Y-%m-%d %H:%M:%S')}] " |
|
|
f"Using cached bhavcopy for {date_str}" |
|
|
) |
|
|
return cached |
|
|
|
|
|
try: |
|
|
|
|
|
|
|
|
|
|
|
try: |
|
|
dt.strptime(date_str, "%d-%m-%Y") |
|
|
except ValueError: |
|
|
html = "<h3>Invalid date format. Use DD-MM-YYYY.</h3>" |
|
|
persist.save(key, html, "html") |
|
|
return html |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
try: |
|
|
df = nse.nse_bhavcopy(date_str) |
|
|
df.columns = df.columns.str.strip() |
|
|
except Exception: |
|
|
html = f"<h3>No Bhavcopy found for {date_str}.</h3>" |
|
|
persist.save(key, html, "html") |
|
|
return html |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
remove = ["DATE1", "LAST_PRICE", "AVG_PRICE"] |
|
|
df.drop(columns=[c for c in remove if c in df.columns], inplace=True) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
numeric_cols = [ |
|
|
"PREV_CLOSE", "OPEN_PRICE", "HIGH_PRICE", "LOW_PRICE", |
|
|
"CLOSE_PRICE", "TTL_TRD_QNTY", "TURNOVER_LACS", |
|
|
"NO_OF_TRADES", "DELIV_QTY", "DELIV_PER" |
|
|
] |
|
|
|
|
|
for col in numeric_cols: |
|
|
if col in df.columns: |
|
|
df[col] = ( |
|
|
df[col] |
|
|
.astype(str) |
|
|
.str.replace(",", "", regex=False) |
|
|
.str.strip() |
|
|
) |
|
|
df[col] = pd.to_numeric(df[col], errors="coerce").fillna(0) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
df = df[df["TURNOVER_LACS"] > 1000] |
|
|
df = df.sort_values("TURNOVER_LACS", ascending=False) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
df["change"] = df["CLOSE_PRICE"] - df["PREV_CLOSE"] |
|
|
df["perchange"] = (df["change"] / df["PREV_CLOSE"].replace(0, 1)) * 100 |
|
|
df["pergap"] = ( |
|
|
(df["OPEN_PRICE"] - df["PREV_CLOSE"]) / |
|
|
df["PREV_CLOSE"].replace(0, 1) |
|
|
) * 100 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
main_html = f""" |
|
|
<div class="main-table-container"> |
|
|
{df.to_html(index=False, escape=False)} |
|
|
</div> |
|
|
""" |
|
|
|
|
|
metrics = ["perchange", "pergap", "TURNOVER_LACS", "NO_OF_TRADES", "DELIV_PER"] |
|
|
col_html = [] |
|
|
|
|
|
for m in metrics: |
|
|
if m in df.columns: |
|
|
temp = df[["SYMBOL", m]].sort_values(m, ascending=False) |
|
|
col_html.append( |
|
|
f""" |
|
|
<div class="col"> |
|
|
<h4>{m}</h4> |
|
|
{temp.to_html(index=False, escape=False)} |
|
|
</div> |
|
|
""" |
|
|
) |
|
|
|
|
|
grid_html = f""" |
|
|
<div class="grid"> |
|
|
{''.join(col_html)} |
|
|
</div> |
|
|
""" |
|
|
|
|
|
css = """ |
|
|
<style> |
|
|
.grid { display: grid; grid-template-columns: repeat(5, 1fr); gap: 10px; } |
|
|
.col, .main-table-container { |
|
|
max-height: 480px; overflow-y: auto; |
|
|
border: 1px solid #ccc; padding: 4px; |
|
|
} |
|
|
table { font-size: 12px; width: 100%; border-collapse: collapse; } |
|
|
th, td { border: 1px solid #ddd; padding: 4px; } |
|
|
th { |
|
|
background: #2E7D32; color: white; |
|
|
position: sticky; top: 0; |
|
|
} |
|
|
</style> |
|
|
""" |
|
|
|
|
|
html = ( |
|
|
css + |
|
|
"<h2>Main Bhavcopy Table</h2>" + |
|
|
main_html + |
|
|
"<h2>Matrix/Grid Table</h2>" + |
|
|
grid_html |
|
|
) |
|
|
|
|
|
persist.save(key, html, "html") |
|
|
return html |
|
|
|
|
|
except Exception as e: |
|
|
print( |
|
|
f"[{dt.now().strftime('%Y-%m-%d %H:%M:%S')}] " |
|
|
f"Error build_bhavcopy_html: {e}" |
|
|
) |
|
|
return f"<h3>Error: {e}</h3>" |
|
|
|