#!/usr/bin/env python3
"""Reconcile prior-report RSI/MACD numbers with today's, and fix volume-ratio convention."""
import json, re
from datetime import date
import numpy as np
import pandas as pd
import yfinance as yf

ema = lambda s, n: s.ewm(span=n, adjust=False).mean()

def rsi_roll(c, n=14):
    d = c.diff(); up = d.clip(lower=0); dn = -d.clip(upper=0)
    rs = (up.rolling(n).mean() / dn.rolling(n).mean()).replace([np.inf, -np.inf], np.nan).fillna(50)
    return 100 - 100 / (1 + rs)

def rsi_wild(c, n=14):
    d = c.diff(); up = d.clip(lower=0); dn = -d.clip(upper=0)
    au = up.ewm(alpha=1/n, adjust=False).mean(); ad = dn.ewm(alpha=1/n, adjust=False).mean()
    rs = (au / ad).replace([np.inf, -np.inf], np.nan).fillna(50)
    return 100 - 100 / (1 + rs)

def parse(path):
    d = json.load(open(path, encoding="utf-8"))
    if d.get("stat") != "OK":
        return None
    rows = []
    for r in d["data"]:
        m = re.match(r'^(\d+)/(\d+)/(\d+)$', r[0].strip()); y = int(m.group(1)) + 1911
        num = lambda x: float(str(x).replace(",", "").replace("+", "").strip())
        rows.append(dict(date=date(y, int(m.group(2)), int(m.group(3))), vol=num(r[1]),
                         open=num(r[3]), high=num(r[4]), low=num(r[5]), close=num(r[6])))
    return pd.DataFrame(rows).set_index("date").sort_index()

fr = [parse(f) for f in ["tw_6669_202604.json", "tw_6669_202605.json", "tw_6669_202606.json",
                         "tw_6669_202607.json", "tw_6669_202608.json", "tw_6669_sep.json", "tw_6669_oct.json"]]
tw = pd.concat([f for f in fr if f is not None])
tw = tw[~tw.index.duplicated(keep="last")].sort_index(); tw = tw[tw["vol"] > 0]
adj = tw.copy()
for c in ["open", "high", "low", "close"]:
    adj[c] = np.where(adj.index < date(2026, 9, 2), adj[c] / 3.0, adj[c])

yh = yf.Ticker("6669.TW").history(period="6mo", auto_adjust=False)
yc_all = yh["Close"].dropna()
yc_clean = yh[yh["Volume"].fillna(0) > 0]["Close"].dropna()

def at(s, dt, fn):
    idx = s.index
    ts = pd.Timestamp(dt)
    ts = ts.tz_localize(idx.tz) if getattr(idx, "tz", None) else ts
    return float(fn(s).loc[ts])

def macd_at(s, dt):
    m = ema(s, 12) - ema(s, 26); sg = ema(m, 9); h = m - sg
    idx = s.index; ts = pd.Timestamp(dt)
    ts = ts.tz_localize(idx.tz) if getattr(idx, "tz", None) else ts
    return float(m.loc[ts]), float(sg.loc[ts]), float(h.loc[ts])

print("=== Reproducing prior 10/29 report (RSI 38.88, MACD -80.66/-65.69/-14.97, MA20 2047.75) ===")
for label, s in [("TWSE-splitadj", adj["close"]), ("Yahoo-clean", yc_clean), ("Yahoo-phantom", yc_all)]:
    for dt in ["2026-10-28", "2026-10-29", "2026-10-30"]:
        try:
            rr = at(s, dt, rsi_roll); rw = at(s, dt, rsi_wild)
            m, sg, hh = macd_at(s, dt)
            ma20 = float(s.rolling(20).mean().loc[pd.Timestamp(dt, tz=getattr(s.index,'tz',None))]) if getattr(s.index,'tz',None) else float(s.rolling(20).mean().loc[pd.Timestamp(dt)])
            ma60 = float(s.rolling(60).mean().loc[pd.Timestamp(dt, tz=getattr(s.index,'tz',None))]) if getattr(s.index,'tz',None) else float(s.rolling(60).mean().loc[pd.Timestamp(dt)])
            print(f"  {label:14s} {dt}: RSIroll={rr:6.2f} RSIwild={rw:6.2f} MACD={m:8.2f} sig={sg:8.2f} hist={hh:7.2f} MA20={ma20:8.2f} MA60={ma60:8.2f}")
        except Exception as e:
            print(f"  {label:14s} {dt}: ERR {e}")

print("\n=== Volume-ratio convention check (TWSE official) ===")
v = tw["vol"]
for dt in ["2026-10-29", "2026-10-30"]:
    i = list(tw.index).index(date(*map(int, dt.split("-"))))
    incl = float(v.iloc[i-19:i+1].mean())
    excl = float(v.iloc[i-20:i].mean())
    print(f"  {dt}: vol={v.iloc[i]:,.0f} 20d incl={incl:,.0f} ratio={v.iloc[i]/incl:.4f} | 20d excl={excl:,.0f} ratio={v.iloc[i]/excl:.4f}")
print("  (prior 10/29 report used 20d incl: 3,547,186 / 4,675,264 = %.4f)" % (3547186/4675264))

print("\n=== 2334.TW via Yahoo ===")
try:
    h4 = yf.Ticker("2334.TW").history(period="3mo", auto_adjust=False)
    c4 = h4["Close"].dropna()
    print(f"  last={c4.index[-1].date()} close={c4.iloc[-1]:.2f} day%={(c4.iloc[-1]/c4.iloc[-2]-1)*100:+.2f} 5d%={(c4.iloc[-1]/c4.iloc[-6]-1)*100:+.2f}")
except Exception as e:
    print("  ERR", repr(e)[:150])
