import json, urllib.request, datetime, time
UA={"User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15"}
def y(sym,rng,iv):
    for host in ("query1","query2"):
        try:
            u=f"https://{host}.finance.yahoo.com/v8/finance/chart/{sym}?interval={iv}&range={rng}"
            d=json.load(urllib.request.urlopen(urllib.request.Request(u,headers=UA),timeout=20))
            r=d["chart"]["result"][0]; q=r["indicators"]["quote"][0]
            out=[{"t":t,"o":o,"h":h,"l":l,"c":c} for t,o,h,l,c in zip(r["timestamp"],q["open"],q["high"],q["low"],q["close"]) if None not in (o,h,l,c)]
            return out, r["meta"]
        except Exception:
            time.sleep(3); continue
    raise RuntimeError("yahoo fail")
def rs(bars,h):
    sec=h*3600; b={}
    for x in bars:
        k=x["t"]-(x["t"]%sec)
        if k not in b: b[k]=dict(x); b[k]["t"]=k
        else:
            z=b[k]; z["h"]=max(z["h"],x["h"]); z["l"]=min(z["l"],x["l"]); z["c"]=x["c"]
    return [b[k] for k in sorted(b)]
def fr(bars,n=2):
    o=[]
    for i in range(n,len(bars)-n):
        w=bars[i-n:i+n+1]
        if bars[i]["h"]==max(x["h"] for x in w): o.append(bars[i]["h"])
        if bars[i]["l"]==min(x["l"] for x in w): o.append(bars[i]["l"])
    return o
def cl(pts,tol):
    pts=sorted(pts); res=[]; cur=[pts[0]]
    for p in pts[1:]:
        c=sum(cur)/len(cur)
        if abs(p-c)<=tol: cur.append(p)
        else: res.append((sum(cur)/len(cur),len(cur))); cur=[p]
    res.append((sum(cur)/len(cur),len(cur))); return res
h1,meta=y("NQ=F","1mo","1h"); time.sleep(1)
d1,_=y("NQ=F","1y","1d"); time.sleep(1)
w1,_=y("NQ=F","5y","1wk")
h4=rs(h1,4); cur=meta["regularMarketPrice"]
TF={"1h":(h1,40,1),"4h":(h4,60,2),"1d":(d1,100,3),"1w":(w1,200,4)}
allc={k:[c for c in cl(fr(b),tol) if c[1]>=2] for k,(b,tol,_) in TF.items()}
flat=sorted([(l,n,k,TF[k][2]) for k,cs in allc.items() for l,n in cs])
merged=[]; g=[flat[0]]
for f in flat[1:]:
    c=sum(x[0] for x in g)/len(g)
    if abs(f[0]-c)<=150: g.append(f)
    else: merged.append(g); g=[f]
merged.append(g)
rows=[]
for grp in merged:
    lvl=sum(x[0]*x[1] for x in grp)/sum(x[1] for x in grp)
    t=sum(x[1] for x in grp); tfs=sorted(set(x[2] for x in grp),key=lambda z:TF[z][2])
    rows.append({"level":round(lvl),"touch":t,"tf":"/".join(tfs),"score":sum(TF[z][2] for z in tfs)+t})
def lab(r): return "강" if (r["score"]>=25 or len(r["tf"].split("/"))>=3) else ("중" if r["score"]>=14 else "약")
for r in rows: r["강도"]=lab(r)
c=[b["c"] for b in d1]
out={"as_of":datetime.datetime.now().isoformat()[:16],"nq":round(cur,2),
"저항":[r for r in sorted(rows,key=lambda r:r["level"]) if r["level"]>=cur][:4],
"지지":[r for r in sorted(rows,key=lambda r:-r["level"]) if r["level"]<cur][:4],
"ma":{"20":round(sum(c[-20:])/20),"50":round(sum(c[-50:])/50),"200":round(sum(c[-200:])/200)}}
json.dump(out,open("levels_NQ.json","w"),ensure_ascii=False,indent=1)
print("완료:", out["nq"])
