"""六月作帳行情:可重現的事件研究 + 0050 季節性回測(FinLab)

兩段:
  1) 事件研究 — 從六月半年報結帳日買進台股加權報酬指數,持有 N 個交易日的前瞻報酬,
     一年一個獨立觀察值,2003–2025 共 23 年。
  2) 0050 實單版 — 把「六月底進場、七月中出場」當成一個季節性策略,用 finlab sim()
     逐年重複,內含交易成本,產出完整互動式回測報告。

執行:pip install finlab,然後 python strategy.py(finlab 需要資料時會自動引導登入)。
"""
import numpy as np
import pandas as pd
from finlab import data
from finlab.backtest import sim

# ── 載入資料 ──────────────────────────────────────────────
bench = data.get("benchmark_return:發行量加權股價報酬指數").iloc[:, 0].dropna()  # 含息報酬指數
close = data.get("price:收盤價")
td = pd.DatetimeIndex(sorted(bench.index))


def june_close(year):
    """該年六月最後一個交易日(半年報結帳日)。"""
    june = td[(td.year == year) & (td.month == 6)]
    return june[-1] if len(june) else None


def forward_return(anchor, entry_offset, hold_days):
    """從 anchor 起算第 entry_offset 個交易日進場,持有 hold_days 個交易日的報酬。"""
    pos = td.get_loc(anchor)
    i_in, i_out = pos + entry_offset, pos + entry_offset + hold_days
    if i_in < 0 or i_out >= len(bench):
        return np.nan
    return bench.iloc[i_out] / bench.iloc[i_in] - 1.0


# ── 1) 事件研究:結帳日買進、持有 N 日 ────────────────────
print("六月結帳日買進加權報酬指數,持有 N 個交易日(2003–2025):")
years = range(2003, 2026)
for hold in [5, 8, 10, 12, 15, 20]:
    rets = np.array([forward_return(june_close(y), 0, hold) for y in years])
    rets = rets[np.isfinite(rets)]
    win = (rets > 0).mean()
    t = rets.mean() / (rets.std(ddof=1) / np.sqrt(len(rets)))
    print(f"  持有 {hold:2d} 日:平均 {rets.mean()*100:+.2f}%  勝率 {win*100:.0f}%  t={t:+.2f}")

# ── 2) 0050 實單版:六月底進場、七月中出場,逐年重複 ───────
# 進場 = 六月結帳日前一個交易日(-1),出場 = 結帳日後第 11 個交易日(約七月中)
ENTRY, EXIT = -1, 11
position = pd.DataFrame(0.0, index=close.index, columns=["0050"])
for y in range(2007, 2026):
    anchor = june_close(y)
    if anchor is None:
        continue
    pos = td.get_loc(anchor)
    if pos + ENTRY < 0 or pos + EXIT >= len(td):
        continue
    hold_days = td[pos + ENTRY: pos + EXIT + 1]
    position.loc[hold_days, "0050"] = 1.0  # 持有期間 100% 押在 0050,其餘時間空手

# finlab sim:ETF 手續費 0.1425%、證交稅 0.1%(ETF 稅率,股票為 0.3%)
report = sim(
    position,
    resample=None,            # 用每日部位,不另外換股
    fee_ratio=0.001425,
    tax_ratio=0.001,
    upload=False,
    name="六月作帳行情 0050 季節性",
)
report.to_html("report_strategy.html")
print("\n已輸出 report_strategy.html")
