Spaces:
Running
Running
File size: 3,761 Bytes
4f453c6 6a45c9c 4f453c6 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 |
# ==============================
# Imports
# ==============================
import requests
import zipfile
from io import BytesIO, StringIO
from datetime import datetime as dt
from typing import Dict, Union
import pandas as pd
# persist helpers
from .persist import exists, load, save
# ==============================
# Raw CSV Loader (NO parsing)
# ==============================
def load_csv(url: str) -> Union[str, Dict[str, str]]:
"""
Pure transport loader
- .csv -> raw CSV text (str)
- .zip -> {filename: raw CSV text}
NO parsing
NO cleaning
NO assumptions
"""
r = requests.get(url)
r.raise_for_status()
if url.lower().endswith(".zip"):
z = zipfile.ZipFile(BytesIO(r.content))
out: Dict[str, str] = {}
for name in z.namelist():
if name.lower().endswith(".csv"):
with z.open(name) as f:
out[name] = f.read().decode("utf-8", errors="ignore")
return out
return r.text
# ==============================
# NSE High-Low HTML Formatter
# ==============================
def _highlow_html_formatter(df: pd.DataFrame, date_str: str) -> str:
metric = "PERCENT_CHANGE"
df_html = df.copy()
top_up = df[metric].nlargest(3).index if metric in df else []
top_dn = df[metric].nsmallest(3).index if metric in df else []
for idx, row in df_html.iterrows():
for col in df_html.columns:
val = row[col]
style = ""
if isinstance(val, (int, float)):
txt = f"{val:.2f}"
if val > 0:
style = "pos"
elif val < 0:
style = "neg"
if col == metric:
if idx in top_up:
style += " top-up"
elif idx in top_dn:
style += " top-down"
df_html.at[idx, col] = f'<span class="{style.strip()}">{txt}</span>'
else:
df_html.at[idx, col] = str(val)
return f"""
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>NSE High-Low {date_str}</title>
<style>
body {{ font-family: Arial; background:#f5f5f5; padding:12px; }}
table {{ border-collapse: collapse; width:100%; background:white; }}
th, td {{ border:1px solid #bbb; padding:6px; font-size:13px; }}
th {{ background:#222; color:white; }}
.pos {{ color:green; font-weight:bold; }}
.neg {{ color:red; font-weight:bold; }}
.top-up {{ background:#b6f2b6; }}
.top-down {{ background:#f2b6b6; }}
</style>
</head>
<body>
<h2>NSE Index High / Low — {date_str}</h2>
{df_html.to_html(index=False, escape=False)}
</body>
</html>
"""
# ==============================
# NSE High-Low Master Function
# ==============================
def nse_highlow(date_str: str | None = None) -> str:
"""
Master NSE High-Low function
Responsibilities:
- Knows NSE CSV structure
- Header starts at row index 2 (skip 0 & 1)
- Uses raw CSV loader
- Builds HTML
- Persists ONLY HTML
"""
if not date_str:
date_str = dt.now().strftime("%d-%m-%Y")
cache_key = f"highlow_{date_str}"
if exists(cache_key, "html"):
return load(cache_key, "html")
d = dt.strptime(date_str, "%d-%m-%Y")
url = (
"https://archives.nseindia.com/content/indices/"
f"ind_close_all_{d.strftime('%d%m%Y')}.csv"
)
# 1️⃣ Load raw CSV text
csv_text = load_csv(url)
# 2️⃣ NSE-specific parsing (header row = 2)
df = pd.read_csv(
StringIO(csv_text),
header=0
)
# 3️⃣ Build HTML
html = _highlow_html_formatter(df, date_str)
# 4️⃣ Persist HTML only
save(cache_key, html, "html")
return html |