#!/usr/bin/env python3
"""Generate the evening-watch HTML + final numbers for 2026-10-26.
Data date: TW 2026-10-22 (10/23 typhoon closure, 10/26 光復節補假). US 2026-10-23."""
import json, os
from datetime import datetime, timezone, timedelta

D = json.load(open("/root/.hermes/cron/output/_clean_20261026.json"))
CL = json.load(open("/root/.hermes/cron/output/_data_20261026.json")).get("cloud", {})
FRED_PATH = "/root/.hermes/cron/output/_fred_20261026.json"
credit = None
if os.path.exists(FRED_PATH):
    try:
        f = json.load(open(FRED_PATH))
        if f.get("BAMLH0A0HYM2") and f.get("BAMLC0A0CM"):
            credit = {"hy": f["BAMLH0A0HYM2"], "ig": f["BAMLC0A0CM"],
                      "spread": f.get("hy_ig_spread_bps")}
    except Exception:
        credit = None

n, a, asia = D["6669"], D["00412A"], D["asia"]
gap = lambda now, thr: (now - thr) / thr * 100

# ---- position math (skill v2 baseline) ----
N9, C9 = 258, 1737.0
N412, C412 = 15000, 9.43
V9, V412 = N9 * n["close"], N412 * a["close"]
K9, K412 = N9 * C9, N412 * C412
TOT, KTOT = V9 + V412, K9 + K412

p9_pct = (V9 / K9 - 1) * 100
p412_pct = (V412 / K412 - 1) * 100
tot_pct = (TOT / KTOT - 1) * 100

# ---- triggers ----
below60 = n["consec_below_ma60"]
full_exit_1 = below60 >= 3
cds = 1194  # 10/21 scanx: "CoreWeave CDS hit 1,194 bps"; 10/15 Reuters/S&P: >1,100 bps
cds_note = "1,194 bps（10/21 報價）"
cds_over_1500 = cds > 1500
hyig_over_500 = bool(credit and credit["spread"] and credit["spread"] > 500)
full_exit_2 = cds_over_1500 and hyig_over_500
full_exit_3 = False  # no hyperscaler capex guidance cut reported
trim_1810 = n["close"] < 1810
trim_1720 = n["close"] < 1720
trim_2030 = n["close"] >= 2030
trim_2128 = n["close"] >= 2128 and n["hist"] < 0
add_rsi = n["rsi"] <= 28
add_vol = n["vol_ratio"] <= 0.70
add_kdj = n["prev_k"] <= n["prev_d"] and n["k"] > n["d"]
add_all = add_rsi and add_vol and add_kdj

stop_412 = a["close"] < 8.00
tp_hit = [t for t in (12.0, 14.0, 16.0) if a["close"] >= t]
hold_412 = 8.50 <= a["close"] <= 12.0

smic = asia.get("SMIC") or {}
sams = asia.get("Samsung") or {}
asia_red = (smic.get("chg_pct") is not None and smic["chg_pct"] <= -3) or \
           (sams.get("chg_pct") is not None and sams["chg_pct"] <= -3)
jpy = asia.get("JPY/TWD") or {}

red_lines, yel_lines, snap = [], [], []
def money(x): return f"{x:,.0f}"

# ---------- RED ----------
red_lines.append(
    f"<b>6669 緯穎 — 已觸發 full-exit 條件 #1</b>：連續 <b>{below60} 個交易日</b>收盤低於 MA60（{n['ma60']:,.0f}），"
    f"且期間成交量整體遞減（10/16 爆量 13,858,059 → 10/22 4,732,956）。skill v2 門檻為「三根連續收盤跌破 MA60 且量縮」，"
    f"實際 {below60} 根遠超標。<span class=\"tag t-red\">FULL EXIT</span></li>")
red_lines.append(
    f"<b>00412A 主動安聯亞半導體 — 無觸發</b>：收盤 {a['close']:.2f}（10/22），距停損 8.00 尚有 {gap(a['close'],8.0):+.1f}%，"
    f"距停利首階 12.00 尚有 {gap(a['close'],12.0):+.1f}%。</li>")
if credit:
    red_lines.append(
        f"<b>信用訊號 — HY-IG OAS {credit['spread']:.0f} bps</b>（HY {credit['hy']['value']:.2f}% / IG {credit['ig']['value']:.2f}%，"
        f"FRED {credit['hy']['date']}）。{'高於' if credit['spread']>500 else '低於'} full-exit 門檻 500 bps。</li>")
else:
    red_lines.append(
        "<b>信用訊號 — N/A</b>：FRED（BAMLH0A0HYM2 / BAMLC0A0CM）端點本時段 HTTP/2 讀取持續逾時，"
        "HTTP/1.1 重試亦失敗，無法取得 HY-IG OAS。依紀律不外推、不以其他指標替代。</li>")
red_lines.append(
    f"<b>雲端 capex — 無已公告下修</b>：三大雲近 3 日同步走弱（GOOGL {CL['GOOGL']['chg3_pct']:.2f}%、"
    f"AMZN {CL['AMZN']['chg3_pct']:.2f}%、MSFT {CL['MSFT']['chg3_pct']:.2f}%），屬股價反應，非 Q4 capex 指引下修 ≥10%。</li>")
red_lines.append(
    f"<b>補充 — CoreWeave 信用風險實質升高</b>：5Y CDS <b>{cds_note}</b>（10/15 Reuters 引 S&P Global Market Intelligence："
    "首度突破 1,100 bps，隱含五年違約率約 64%）；CRWV 股價 10/23 收 54.24（5 日 −11.7%）。"
    "因 CDS 尚未站上 1,500 bps 門檻，full-exit 條件 #2 未成立（且 HY-IG 為 N/A，雙條件無法同時判定）。</li>")

# ---------- YELLOW ----------
yel_lines.append(
    f"<b>6669 距減碼線僅 {gap(n['close'],1810):+.1f}%</b>：收盤 {n['close']:,.0f} vs 20 日低點 {n['low20']:,.0f}"
    "（觸發即減 100 股）。跌破後下一階為結構性跌破 1,720（再減 100 股，剩 58 股）。</li>")
yel_lines.append(
    f"<b>MACD 柱狀體仍為負且未收斂</b>：Hist {n['hist']:.2f}（前日 −33.66），MACD {n['macd']:.2f} / Signal {n['signal']:.2f}。</li>")
yel_lines.append(
    f"<b>K/D 死叉未解</b>：K {n['k']:.2f} 低於 D {n['d']:.2f}（超賣但未黃金交叉）。"
    f"加碼三條件僅 RSI 接近（{n['rsi']:.2f} vs ≤28，{gap(n['rsi'],28):+.1f}%），量 {n['vol_ratio']:.2f}x（門檻 ≤0.7x）、黃金交叉皆未達。</li>")
yel_lines.append(
    f"<b>SOX 距 60 日高點 {asia['SOX']['from_high60_pct']:.1f}%</b>：10/23 收 {asia['SOX']['close']:,.0f}"
    f"（單日 {asia['SOX']['chg_pct']:+.2f}%），5 日累計 {asia['SOX']['chg5_pct']:.2f}%。</li>")
smic_s = f"中芯 {smic['chg_pct']:+.2f}%" if smic.get("chg_pct") is not None else "中芯 N/A"
sam_s = f"三星 {sams['chg_pct']:+.2f}%" if sams.get("chg_pct") is not None else "三星 N/A"
yel_lines.append(
    f"<b>亞半導體供應鏈壓力加劇</b>：10/26 亞股 {smic_s}（5 日 {smic.get('chg5_pct',0):.1f}%）、{sam_s}"
    f"（5 日 {sams.get('chg5_pct',0):.1f}%）、日經 {asia['Nikkei']['chg_pct']:+.2f}%；"
    f"台股部分（10/22）：台積電 {asia['TSMC TW']['chg_pct']:+.2f}%、華邦電 5 日 {asia['華邦電']['chg5_pct']:.2f}%、"
    f"台達電 5 日 {asia['台達電']['chg5_pct']:.2f}%。單日均未達 −3% 區域壓力紅線，但中芯 5 日已 −12.4%。</li>")
if jpy.get("chg5_pct") is not None:
    yel_lines.append(
        f"<b>日圓/台幣 5 日 {jpy['chg5_pct']:+.1f}%</b>：未達 5% 升值門檻，亞洲半導體資金撤出風險暫無訊號。</li>")

# ---------- snapshot ----------
snap.append(f"<tr><td>6669 收盤</td><td>{n['close']:,.2f}（2026-10-22）</td>"
            f"<td>MA20 {n['ma20']:,.0f}（{gap(n['close'],n['ma20']):+.1f}%）</td></tr>")
snap.append(f"<tr><td>6669 RSI(14)</td><td>{n['rsi']:.2f}</td><td>未達加碼門檻 ≤28</td></tr>")
snap.append(f"<tr><td>6669 MACD / Hist</td><td>{n['macd']:.2f} / {n['hist']:.2f}</td>"
            f"<td style=\"color:#f85149\">空方，未收斂</td></tr>")
snap.append(f"<tr><td>6669 K / D</td><td>{n['k']:.2f} / {n['d']:.2f}</td><td style=\"color:#f85149\">死叉</td></tr>")
snap.append(f"<tr><td>6669 量 / 20 日均量</td><td>{n['volume']:,} / {n['vma20']:,.0f}（{n['vol_ratio']:.2f}x）</td>"
            f"<td>量未縮（門檻 ≤0.7x）</td></tr>")
snap.append(f"<tr><td>6669 20 日低點</td><td>{n['low20']:,.0f}（10/19 盤中）</td>"
            f"<td>減碼線 1,810，距 {gap(n['close'],1810):+.1f}%</td></tr>")
snap.append(f"<tr><td>6669 跌破 MA60 天數</td><td style=\"color:#f85149\">{below60} 日（自 10/14 起）</td>"
            f"<td><span class=\"tag t-red\">FULL EXIT #1</span></td></tr>")
snap.append(f"<tr><td>6669 距 60 日高</td><td style=\"color:#f85149\">{n['from_high60_pct']:.1f}%（高 {n['high60']:,.0f}）</td>"
            f"<td>距 MA60 {gap(n['close'],n['ma60']):+.1f}%</td></tr>")
snap.append(f"<tr><td>00412A 主動安聯亞半導體 收盤</td><td>{a['close']:.2f}（2026-10-22）</td>"
            f"<td>停損 8.00（{gap(a['close'],8.0):+.1f}%）／停利 12.00</td></tr>")
snap.append(f"<tr><td>00412A 有效收盤筆數</td><td>{a['bars']} 筆（10/13 上市首日 ~ 10/22）</td>"
            f"<td>無技術面（上市 &lt; 30 日）</td></tr>")
snap.append(f"<tr><td>00412A 上市以來區間</td><td>{a['low']:.2f} ~ {a['high']:.2f}</td>"
            f"<td>現價貼近上市以來低點</td></tr>")
snap.append(f"<tr><td>SOX 指數</td><td>{asia['SOX']['close']:,.0f}（10/23）</td>"
            f"<td style=\"color:#f85149\">5 日 {asia['SOX']['chg5_pct']:.2f}%／距 60 日高 {asia['SOX']['from_high60_pct']:.1f}%</td></tr>")
snap.append(f"<tr><td>AMZN / MSFT / GOOGL</td><td>{CL['AMZN']['close']:.2f} / {CL['MSFT']['close']:.2f} / {CL['GOOGL']['close']:.2f}（10/23）</td>"
            f"<td style=\"color:#f85149\">3 日 {CL['AMZN']['chg3_pct']:.2f}% / {CL['MSFT']['chg3_pct']:.2f}% / {CL['GOOGL']['chg3_pct']:.2f}%</td></tr>")
snap.append(f"<tr><td>CRWV（CoreWeave）</td><td>{asia['CoreWeave']['close']:.2f}</td>"
            f"<td style=\"color:#f85149\">5 日 {asia['CoreWeave']['chg5_pct']:.1f}%</td></tr>")
if credit:
    snap.append(f"<tr><td>HY-IG OAS</td><td>{credit['spread']:.0f} bps</td>"
                f"<td>HY {credit['hy']['value']:.2f}% / IG {credit['ig']['value']:.2f}%（{credit['hy']['date']}）</td></tr>")
else:
    snap.append("<tr><td>HY-IG OAS</td><td>N/A</td><td>FRED 端點逾時，未外推</td></tr>")
snap.append(f"<tr><td>CoreWeave 5Y CDS</td><td>{cds_note}</td>"
            f"<td>10/15 首破 1,100 bps；門檻 1,500 bps 未到</td></tr>")

now = datetime.now(timezone(timedelta(hours=8)))
ts = now.strftime("%Y-%m-%d %H:%M (UTC+8)")

html = f"""<!DOCTYPE html>
<html lang="zh-Hant"><head><meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>AI 持倉盤後警訊 2026-10-26</title>
<style>
:root{{--bg:#0d1117;--fg:#e6edf3;--dim:#8b949e;--card:#161b22;--bd:#30363d;--red:#f85149;--yel:#d29922;--grn:#3fb950;--blu:#58a6ff}}
*{{box-sizing:border-box}}
body{{margin:0;padding:24px;background:var(--bg);color:var(--fg);font-family:"Noto Sans TC","PingFang TC","Microsoft JhengHei",system-ui,sans-serif;line-height:1.65}}
.wrap{{max-width:880px;margin:0 auto}}
h1{{font-size:22px;margin:0 0 4px;letter-spacing:.5px}}
.sub{{color:var(--dim);font-size:13px;margin-bottom:20px}}
.card{{background:var(--card);border:1px solid var(--bd);border-radius:10px;padding:16px 18px;margin-bottom:14px}}
.card h2{{font-size:15px;margin:0 0 12px;display:flex;align-items:center;gap:8px}}
.dot{{width:9px;height:9px;border-radius:50%;display:inline-block;flex:none}}
.red{{background:var(--red)}}.yel{{background:var(--yel)}}.grn{{background:var(--grn)}}.blu{{background:var(--blu)}}
ul{{margin:0;padding-left:20px}}li{{margin-bottom:8px;font-size:14px}}
b{{color:#fff;font-weight:600}}
table{{width:100%;border-collapse:collapse;font-size:13px;font-variant-numeric:tabular-nums}}
th,td{{padding:8px 10px;text-align:left;border-bottom:1px solid var(--bd);vertical-align:top}}
th{{color:var(--dim);font-weight:500;font-size:12px;letter-spacing:.5px}}
tr:last-child td{{border-bottom:none}}
.tag{{display:inline-block;padding:2px 8px;border-radius:20px;font-size:11px;font-weight:600;white-space:nowrap}}
.t-red{{background:rgba(248,81,73,.15);color:var(--red);border:1px solid rgba(248,81,73,.4)}}
.note{{color:var(--dim);font-size:12px;margin-top:12px;padding-top:10px;border-top:1px dashed var(--bd)}}
footer{{text-align:center;color:var(--dim);font-size:12px;margin-top:22px}}
</style></head><body><div class="wrap">

<h1>【AI 持倉盤後警訊】2026-10-26（週一）</h1>
<div class="sub">台股資料截至 <b>2026-10-22</b> 收盤（10/23 颱風「香巴米」休市、10/26 光復節補假，連續兩個休市日）｜美國盤 2026-10-23 收盤｜本報告排程於 {ts} 產生</div>

<div class="card">
<h2><span class="dot red"></span>🔴 觸發警示</h2>
<ul>
{"".join(red_lines)}
</ul>
</div>

<div class="card">
<h2><span class="dot yel"></span>🟡 觀察中</h2>
<ul>
{"".join(yel_lines)}
</ul>
</div>

<div class="card">
<h2><span class="dot grn"></span>🟢 部位狀態</h2>
<table>
<tr><th>部位</th><th>持股</th><th>成本</th><th>現價</th><th>市值</th><th>P&amp;L</th><th>報酬</th></tr>
<tr><td>6669 緯穎</td><td>258</td><td>1,737</td><td>{n['close']:,.2f}</td><td>{money(V9)}</td>
    <td style="color:#3fb950">+{money(V9-K9)}</td><td style="color:#3fb950">+{p9_pct:.2f}%</td></tr>
<tr><td>00412A 主動安聯亞半導體</td><td>15,000</td><td>9.43</td><td>{a['close']:.2f}</td><td>{money(V412)}</td>
    <td style="color:#f85149">−{money(K412-V412)}</td><td style="color:#f85149">{p412_pct:.2f}%</td></tr>
<tr><td><b>合計</b></td><td>—</td><td>{money(KTOT)}</td><td>—</td><td><b>{money(TOT)}</b></td>
    <td style="color:#3fb950"><b>+{money(TOT-KTOT)}</b></td><td style="color:#3fb950"><b>+{tot_pct:.2f}%</b></td></tr>
</table>
<div class="note">市值與損益以 10/22 收盤計（10/26 休市無新價）。6669 安全墊 +{p9_pct:.2f}%；00412A 上市以來自首日 9.75 累計 {gap(a['close'],a['first_close']):+.1f}%。</div>
</div>

<div class="card">
<h2><span class="dot blu"></span>📋 明日決策</h2>
<ul>
<li><b>6669：條件已達 — 建議執行 full exit</b>。連 {below60} 日收盤低於 MA60 且量縮，MA60 遠在 {gap(n['close'],n['ma60']):.1f}% 之上，屬明確趨勢破壞而非雜訊。技術面 RSI {n['rsi']:.2f} 尚未超賣、MACD 柱狀體未轉正、SOX 同步破位，無技術性反轉支撐。建議<b>分批出場</b>而非一次砍在低點：反彈至 1,950–2,030 分批減碼；若直接跌破 1,810 則不戀戰執行。RSI 未破 28 且量未縮至 0.7x 以下前不建議加碼。</li>
<li><b>00412A：觀望</b>。收盤 {a['close']:.2f} 位於 8.50–12.00 持有區，距停損 8.00 有 {gap(a['close'],8.0):+.1f}% 緩衝，未觸發任何條件。上市僅 {a['bars']} 筆有效收盤，無技術面，純以停損 8.00 與停利階梯管理。10/22 盤中低 8.87 距停損僅 +10.9%，建議設 8.00 硬性停損單並留意亞半導體情緒（中芯 5 日 −12.4%、SOX 距高 −19.3%）。</li>
</ul>
</div>

<div class="card">
<h2><span class="dot blu"></span>📊 訊號快照</h2>
<table>
<tr><th>指標</th><th>數值</th><th>狀態</th></tr>
{"".join(snap)}
</table>
</div>

<footer>📌 由 ai-portfolio-evening-watch v2 自動產生 · {ts}</footer>
</div></body></html>
"""

out = "/root/.hermes/cron/output/portfolio-evening-2026-10-26.html"
open(out, "w").write(html)
print("WROTE", out, os.path.getsize(out), "bytes")
print("credit:", credit)
print(f"P&L: 6669 {V9:,.0f} ({p9_pct:+.2f}%) | 00412A {V412:,.0f} ({p412_pct:+.2f}%) | TOTAL {TOT:,.0f} ({tot_pct:+.2f}%)")
print("triggers: full_exit_1", full_exit_1, "| full_exit_2", full_exit_2, "| full_exit_3", full_exit_3,
      "| trim_1810", trim_1810, "| trim_1720", trim_1720, "| trim_2030", trim_2030, "| trim_2128", trim_2128,
      "| add_all", add_all, "| asia_red", asia_red, "| stop_412", stop_412, "| tp_hit", tp_hit)
