"""照 00981A 揭露的持股權重複製，比較延遲天數與調整頻率；研究用途，不構成投資建議。"""
from functools import lru_cache

import pandas as pd
from finlab import data
from finlab.backtest import sim

START, END = "2025-05-27", "2026-11-11"
ETF = "00981A"


@lru_cache(None)
def target_weights():
    """00981A 每個揭露日的台股持股權重，持續到下一次揭露；其餘是現金。"""
    raw = pd.DataFrame(data.get("tw_active_etf_holdings_history"))
    raw = raw[raw["symbol"].astype(str).eq(ETF)]
    h = pd.DataFrame({"stock": raw["constituent_id"].astype(str),
                      "date": pd.to_datetime(raw["date"].astype(str)),
                      "weight": raw["weight"] / 100})
    calendar = pd.DataFrame(data.get("price:收盤價")).loc[:END]
    h = h[h["stock"].isin(calendar.columns) & h["date"].le(END)]
    weights = h.pivot_table(index="date", columns="stock", values="weight", aggfunc="sum", fill_value=0)
    return weights.reindex(calendar.index).ffill().fillna(0)


def build_position(delay=1):
    """D 日揭露的權重在 D+delay 日開盤成交（sim 本身會晚一天成交）。"""
    return target_weights().shift(delay - 1).loc[START:END].fillna(0)


def rebalance_dates(freq):
    days = build_position().index.to_series()
    ends = days.resample({"W": "W-FRI", "M": "ME"}[freq]).last().dropna()
    return pd.DatetimeIndex([days.index[0], *ends])


def build_report(delay=1, freq="D"):
    position = build_position(delay)
    # 每日：權重一變就調整；每週、每月：只在期末換成最新權重
    options = {} if freq == "D" else {"resample": rebalance_dates(freq)}
    # sim 使用台股預設手續費與證交稅
    return sim(position, trade_at_price="open", upload=False, **options)


if __name__ == "__main__":
    build_report().to_html("report_strategy.html")
