#!/usr/bin/env python3
"""nq_levels.py — NQ 멀티 타임프레임(1h/4h/1d/1w) 통합 지지저항.
각 TF에서 1차 클러스터 → TF 넘어 통합 → 최종 지지/저항 2~3개만. 강도 = TF가중치 + 터치횟수."""
import argparse, json, urllib.request, urllib.parse
import pandas as pd
import yfinance as yf

TICKER = "NQ=F"
BOT_TOKEN = "8996188792:AAGWMYLHXpkjKp0rDToIB6PifC4AjNVG7nc"
CHAT_ID = "6335258875"

TFS = [
    {"name":"1h","period":"2mo","interval":"1h","resample":None,"weight":1,"tol":40.0},
    {"name":"4h","period":"6mo","interval":"1h","resample":"4h","weight":2,"tol":60.0},
    {"name":"1d","period":"1y","interval":"1d","resample":None,"weight":3,"tol":100.0},
    {"name":"1w","period":"5y","interval":"1wk","resample":None,"weight":4,"tol":200.0},
]
MERGE_TOL = 90.0
TOP_N = 3

def pivots(h, l, left=3, right=3):
    sh, sl = [], []
    for i in range(left, len(h)-right):
        if all(h[i]>=h[i-j] for j in range(1,left+1)) and all(h[i]>=h[i+j] for j in range(1,right+1)):
            sh.append(h[i])
        if all(l[i]<=l[i-j] for j in range(1,left+1)) and all(l[i]<=l[i+j] for j in range(1,right+1)):
            sl.append(l[i])
    return sh, sl

def tf_cluster(vals, tol):
    if not vals: return []
    vals = sorted(vals)
    groups, cur = [], [vals[0]]
    for x in vals[1:]:
        if x-cur[-1] <= tol: cur.append(x)
        else: groups.append(cur); cur=[x]
    groups.append(cur)
    return [(round(sum(g)/len(g),1), len(g)) for g in groups]

def merge_cluster(points, tol):
    if not points: return []
    points = sorted(points, key=lambda p: p[0])
    groups, cur = [], [points[0]]
    for p in points[1:]:
        if p[0]-cur[-1][0] <= tol: cur.append(p)
        else: groups.append(cur); cur=[p]
    groups.append(cur)
    order = ["1h","4h","1d","1w"]
    out = []
    for g in groups:
        tfs = sorted({p[1] for p in g}, key=lambda t: order.index(t))
        tf_w = sum({p[1]: p[2] for p in g}.values())
        touches = max(p[3] for p in g)
        out.append({"value": round(sum(p[0] for p in g)/len(g),1),
                    "touches": touches, "tfs": tfs, "score": tf_w+touches})
    return out

def strength(c):
    if c["score"] >= 10 or len(c["tfs"]) >= 3: return "강"
    if c["score"] >= 5 or len(c["tfs"]) >= 2: return "중"
    return "약"

def fetch(cfg):
    df = yf.download(TICKER, period=cfg["period"], interval=cfg["interval"], progress=False)
    if len(df)==0: raise RuntimeError("no data")
    if isinstance(df.columns, pd.MultiIndex): df.columns = df.columns.droplevel(1)
    if cfg["resample"]:
        df = df.resample(cfg["resample"]).agg({"Open":"first","High":"max","Low":"min","Close":"last"}).dropna()
    return df

def run():
    all_h, all_l, last = [], [], None
    for cfg in TFS:
        try:
            df = fetch(cfg)
            h=[float(x) for x in df["High"].values]; l=[float(x) for x in df["Low"].values]
            c=[float(x) for x in df["Close"].values]
            if cfg["name"]=="1h": last=c[-1]
            sh, sl = pivots(h,l)
            all_h += [(v,cfg["name"],cfg["weight"],n) for v,n in tf_cluster(sh,cfg["tol"])]
            all_l += [(v,cfg["name"],cfg["weight"],n) for v,n in tf_cluster(sl,cfg["tol"])]
        except Exception: pass
    if last is None: raise RuntimeError("1h 데이터 실패")
    res = sorted([c for c in merge_cluster(all_h,MERGE_TOL) if c["value"]>=last], key=lambda c:c["value"])[:TOP_N]
    sup = sorted([c for c in merge_cluster(all_l,MERGE_TOL) if c["value"]<=last], key=lambda c:-c["value"])[:TOP_N]
    for c in res+sup: c["strength"] = strength(c)
    dd = yf.download(TICKER, period="1y", interval="1d", progress=False)
    if isinstance(dd.columns, pd.MultiIndex): dd.columns = dd.columns.droplevel(1)
    dc=[float(x) for x in dd["Close"].values]
    ma = {f"{p}일선": round(sum(dc[-p:])/p,1) for p in (20,50,200)}
    return {"last": round(last,2), "resistances": res, "supports": sup, "ma": ma}

def fmt(r):
    L = [f"[NQ 지지저항] 현재가 {r['last']:,.0f}", "", "저항"]
    for c in r["resistances"]:
        L.append(f"  {c['value']:,.0f}  {c['strength']}  (터치{c['touches']}·{'/'.join(c['tfs'])})")
    L.append("지지")
    for c in r["supports"]:
        L.append(f"  {c['value']:,.0f}  {c['strength']}  (터치{c['touches']}·{'/'.join(c['tfs'])})")
    L += ["", "이평(일봉): " + " / ".join(f"{k} {v:,.0f}" for k,v in r["ma"].items())]
    return "\n".join(L)

def send_telegram(msg):
    url = f"https://api.telegram.org/bot{BOT_TOKEN}/sendMessage"
    data = urllib.parse.urlencode({"chat_id": CHAT_ID, "text": msg}).encode()
    with urllib.request.urlopen(url, data=data, timeout=20) as r:
        return r.status

if __name__ == "__main__":
    ap = argparse.ArgumentParser()
    ap.add_argument("--text", action="store_true")
    ap.add_argument("--telegram", action="store_true")
    a = ap.parse_args()
    rep = run(); msg = fmt(rep)
    print(msg if (a.text or a.telegram) else json.dumps(rep, ensure_ascii=False, indent=2))
    if a.telegram:
        print("telegram:", send_telegram(msg))
