"""可轉債選股：月營收動能選股，避開有流通在外可轉債的公司。

與 https://finlab.finance/blog/convertible-bond-stock-selection 同一份程式。
回測從 2010-02 起（FinLab 可轉債每日報表從 2009-12-30 開始）到最新資料。

執行前先安裝 finlab，需要資料時 finlab 會自動引導登入：

    pip install finlab
    python strategy.py
"""
from finlab import data
from finlab.backtest import sim

close = data.get("price:收盤價")
rev = data.get("monthly_revenue:當月營收")
cb = data.get("cb_published_info")

# 1. 月營收動能：近三個月平均營收高於近十二個月平均營收
rev_up = rev.average(3) > rev.average(12)

# 2. 股價趨勢：收盤價同時站上 20、60、120 日均線
trend = (
    (close > close.average(20))
    & (close > close.average(60))
    & (close > close.average(120))
)

# 3. 當天有流通在外可轉債的公司
#    可轉債代號前四碼是發行公司股票代號；債券簡稱含「E + 數字」的是交換債
#    （例如遠紡E1，標的是別家公司股票），不算發行公司自己的可轉債。
own_cb = cb[~cb["債券簡稱"].astype(str).str.contains(r"E\d")]
own_cb = own_cb.assign(stock_id=own_cb["symbol"].astype(str).str[:4])
has_cb = own_cb.groupby(["date", "stock_id"]).size().unstack().notna()
has_cb = has_cb.reindex(close.index).ffill(limit=5).fillna(False).astype(bool)
has_cb = has_cb.reindex(columns=close.columns, fill_value=False).astype(bool)

# 4. 五日平均漲跌幅最強的 10 檔，排除有可轉債的公司
pct_change = (close / close.shift() - 1).rolling(5).mean()
position = pct_change[trend & rev_up & ~has_cb].is_largest(10).loc["2010-02-01":]

# 每月營收公布後（月初第 11 天）換股，單檔 10% 停損，手續費與證交稅用 sim 預設
report = sim(
    position,
    resample="M",
    resample_offset="11D",
    stop_loss=0.1,
    upload=False,
    name="月營收動能避開可轉債發行公司",
)
print(report.get_stats())
