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