"""M19 教学图：公告后才能成交的收益，以及 SUE 分母是否含进当期意外。

价格和每股盈余都是给定的教学序列，不是某次财报的历史漂移。
"""

from __future__ import annotations

from pathlib import Path

import matplotlib.pyplot as plt
import numpy as np

plt.rcParams["font.sans-serif"] = ["Microsoft YaHei", "SimHei", "DejaVu Sans"]
plt.rcParams["axes.unicode_minus"] = False

OUT = Path(__file__).resolve().parent / "event_timing_and_sue.png"


def sue(unexpected: float, history: np.ndarray) -> tuple[float, float]:
    # 样本标准差用 n-1。历史里不能含正在公布的这一期。
    sigma = float(history.std(ddof=1))
    return unexpected / sigma, sigma


def beta_alpha(stock: np.ndarray, market: np.ndarray) -> tuple[float, float]:
    design = np.column_stack([np.ones(len(market)), market])
    coef, *_ = np.linalg.lstsq(design, stock, rcond=None)
    return float(coef[0]), float(coef[1])


def main() -> None:
    # 公告在收盘之后。100 是公告前收盘，103 是下一交易日开盘。
    prev_close = 100.0
    next_open = 103.0
    effective_close = 104.0
    later_close = 102.0
    gap = next_open / prev_close - 1.0
    close_to_effective = effective_close / prev_close - 1.0
    open_to_effective = effective_close / next_open - 1.0
    open_to_later = later_close / next_open - 1.0
    print("gap", f"{gap:.6f}")
    print("close_to_effective", f"{close_to_effective:.6f}")
    print("open_to_effective", f"{open_to_effective:.6f}")
    print("open_to_later", f"{open_to_later:.6f}")

    history = np.array([0.10, -0.05, 0.20, 0.00])
    current = 0.30
    sue_ok, sigma = sue(current, history)
    sue_leaky, sigma_leaky = sue(current, np.append(history, current))
    print("sigma", f"{sigma:.6f}", "sue", f"{sue_ok:.6f}")
    print("sigma_with_current", f"{sigma_leaky:.6f}", "sue_leaky", f"{sue_leaky:.6f}")
    print("stale_surprise", f"{1.50 - 1.20:.2f}")
    print("fresh_surprise", f"{1.50 - 1.45:.2f}")

    market = np.array([0.01, -0.02, 0.015, 0.005, -0.01])
    stock = np.array([0.012, -0.018, 0.020, 0.004, -0.008])
    alpha, beta = beta_alpha(stock, market)
    event_stock, event_market = 0.04, 0.005
    abnormal = event_stock - (alpha + beta * event_market)
    alpha_b, beta_b = beta_alpha(
        np.append(stock, event_stock), np.append(market, event_market)
    )
    abnormal_b = event_stock - (alpha_b + beta_b * event_market)
    print("alpha", f"{alpha:.6f}", "beta", f"{beta:.6f}", "ar", f"{abnormal:.6f}")
    print("beta_incl", f"{beta_b:.6f}", "ar_incl", f"{abnormal_b:.6f}")

    fig, axes = plt.subplots(1, 2, figsize=(11.2, 4.8))
    ax = axes[0]
    labels = ["收盘到生效收盘", "开盘到生效收盘", "开盘到其后收盘"]
    heights = [close_to_effective * 100, open_to_effective * 100, open_to_later * 100]
    colors = ["#a33b3b" if value < 0 else "#1f4e79" for value in heights]
    ax.bar(labels, heights, color=colors)
    ax.axhline(0.0, color="#333333", linewidth=0.8)
    ax.tick_params(axis="x", labelsize=8)
    ax.set_ylabel("收益（%）")
    ax.set_title("公告在收盘之后，开盘已是 103")
    ax = axes[1]
    ax.bar(["不含当期", "分母含当期"], [sue_ok, sue_leaky], color=["#1f4e79", "#c4a35a"])
    ax.set_ylabel("SUE")
    ax.set_title("意外 0.30，历史四期")
    fig.suptitle("M19：能成交的收益和 SUE 的分母；不是历史财报漂移")
    fig.tight_layout()
    fig.savefig(OUT, dpi=140)
    print("wrote", OUT)


if __name__ == "__main__":
    main()
