# -*- coding: utf-8 -*-
"""獲利品質(營業利益率)+ 動能 + 低波 三因子 — finlab 台股真實回測(可重現)。

對應文章:https://finlab.finance/blog/pi-agent-finlab-local-backtest
回測區間:2018-01-01 ~ 2026-06-09(全站 canonical 快照日)
基準:0050 含息(etl:adj_close 還原價買進持有)
成本:finlab sim() 台股預設(手續費 0.1425%、賣出證交稅 0.3%),未另設滑價

這支用「營業利益率」當品質因子(本業賺錢能力),和用 ROE 的版本是一組可互相對照的實驗;
在本地端跑不限次數、資料不出本機,很適合拿來反覆替換因子做比較。

執行:
  cd ~/Documents/finlab && UV_ENV_FILE=.env uv run --with finlab python strategy.py

本程式僅供量化研究與教學,過去績效不代表未來表現,不構成任何投資建議。
"""
import finlab
from finlab import data
from finlab.backtest import sim

finlab.login()

# 1) 載入資料
close = data.get("price:收盤價")
volume = data.get("price:成交股數")
operating_margin = data.get("fundamental_features:營業利益率").index_str_to_date()
operating_margin = operating_margin.reindex(close.index, method="ffill")

# 2) 流動性過濾
amount = (close * volume).rolling(20).mean()
liquid = (amount > 10_000_000) & close.notna()

# 3) 三個因子:獲利品質 + 動能 + 低波
rank_margin = operating_margin.where(liquid).rank(axis=1, pct=True)
rank_momentum = close.pct_change(120).where(liquid).rank(axis=1, pct=True)
volatility = close.pct_change().rolling(60).std()
rank_low_vol = volatility.where(liquid).rank(axis=1, pct=True, ascending=False)
score = rank_margin + rank_momentum + rank_low_vol

# 4) 取前 20 名,分數平方加權,每月再平衡
top20 = score.rank(axis=1, ascending=False) <= 20
weight = (score[top20].fillna(0)) ** 2
weight = weight.div(weight.sum(axis=1), axis=0)

report = sim(weight, resample="M", name="獲利品質動能低波")
report.display()
