1.概述

事件研究法是一种统计方法,用于评估特定事件(如财报发布、并购公告、政策变更等)对资产价格(通常是股票收益率)的影响。其核心逻辑是将实际观测到的收益率与“如果没有发生该事件”情况下的预期正常收益率进行比较,两者的差额即为异常收益率 (Abnormal Return, AR)。其核心步骤如下:

  1. 1. 定义事件与窗口

    • • 事件日 (Event Date):消息公开的那一天。

    • • 估计窗口 (Estimation Window):用于估算股票正常表现参数的时间段(通常在事件前较远处,如 [-120, -21] 天)。

    • • 事件窗口 (Event Window):用于观察事件影响的时间段(如 [-5, +5] 天)。

  2. 2. 建立期望收益模型

    • • 常用市场模型 (Market Model):通过回归分析 ,利用估计窗口的数据计算出  和 。

    • •  是个股收益, 是市场收益。

  3. 3. 计算异常收益 (AR)

    • • 

    • • 即:实际收益减去模型预测的正常收益。

  4. 4. 计算累计异常收益 (CAR)

    • • 

    • • 将事件窗口内的异常收益累加,以衡量事件的总体影响。

  5. 5. 统计检验

    • • 对 AR 和 CAR 进行 t 检验,判断其是否显著异于零,从而确定事件是否具有统计学意义上的影响。

2.代码实现

import pandas as pd
import numpy as np
import statsmodels.api as sm

def run_event_study(data, event_date, ticker_col='ticker', date_col='date', return_col='return', window=(-5, 5)):

    # 1. 数据预处理:计算市场平均收益作为基准模型 (简化版 Market Model)
    # 假设数据中已包含市场收益率或在此处计算等权市场收益
    if 'market_return' not in data.columns:
        data['market_return'] = data.groupby(date_col)[return_col].transform('mean')

    results = []
    
    # 获取唯一股票列表
    tickers = data[ticker_col].unique()
    
    for ticker in tickers:
        stock_data = data[data[ticker_col] == ticker].copy()
        stock_data = stock_data.sort_values(by=date_col)
        
        # 确定事件日在时间序列中的位置
        if event_date not in stock_data[date_col].values:
            continue
            
        event_idx = stock_data[stock_data[date_col] == event_date].index[0]
        all_indices = stock_data.index.tolist()
        event_pos = all_indices.index(event_idx)
        
        # 定义估计窗口 (例如事件前 120 天到前 20 天) 和 事件窗口
        est_start_pos = max(0, event_pos - 120)
        est_end_pos = max(0, event_pos - 21)
        
        if est_end_pos <= est_start_pos:
            continue
            
        est_window_data = stock_data.iloc[est_start_pos:est_end_pos+1]
        
        # 2. 估计正常收益 (使用 OLS 回归: R_i = alpha + beta * R_m + epsilon)
        X = sm.add_constant(est_window_data['market_return'])
        y = est_window_data[return_col]
        model = sm.OLS(y, X).fit()
        
        # 3. 计算事件窗口内的异常收益 (AR)
        event_start_pos = max(0, event_pos + window[0])
        event_end_pos = min(len(stock_data)-1, event_pos + window[1])
        
        event_window_data = stock_data.iloc[event_start_pos:event_end_pos+1].copy()
        
        if len(event_window_data) == 0:
            continue
            
        X_event = sm.add_constant(event_window_data['market_return'])
        predicted_return = model.predict(X_event)
        event_window_data['abnormal_return'] = event_window_data[return_col] - predicted_return
        event_window_data['relative_day'] = range(window[0] + (event_start_pos - (event_pos + window[0])), 
                                                  window[0] + (event_start_pos - (event_pos + window[0])) + len(event_window_data))
        
        # 4. 计算累计异常收益 (CAR)
        event_window_data['car'] = event_window_data['abnormal_return'].cumsum()
        event_window_data[ticker_col] = ticker
        
        results.append(event_window_data[[ticker_col, date_col, 'relative_day', 'abnormal_return', 'car']])
    
    if not results:
        return pd.DataFrame()
        
    final_result = pd.concat(results)
    # 按相对日期聚合平均 CAR
    avg_car = final_result.groupby('relative_day')[['abnormal_return', 'car']].mean().reset_index()
    return avg_car

3.结果展示

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐