市场有效性假说:弱式、半强式与强式市场的实战检验

各位同学,今天我们来聊一个在量化投资里绕不开的话题——市场有效性假说。

说实话,我刚入行那会儿,觉得这玩意儿就是个学术概念,跟实战没啥关系。直到有一次,我花了两周时间打磨了一个看似完美的技术指标策略,结果回测曲线漂亮得不像话,一上实盘就亏得亲妈都不认识。嗯,从那以后,我再也不敢小瞧市场有效性了。

什么是市场有效性假说?

简单说,这个假说就是问一个问题:市场价格到底反映了多少信息?

你想想看,如果股价已经把所有人都知道的信息都消化了,那你凭什么比别人赚得多?这就是有效市场的核心逻辑。

尤金·法玛在1970年把这玩意儿分成了三个层次:

  • 弱式有效:价格已经反映了所有历史交易信息(价格、成交量等)
  • 半强式有效:价格反映了所有公开信息(财报、新闻、公告等)
  • 强式有效:价格反映了所有信息,包括内幕消息

我个人习惯把这三个层次想象成三个筛子。弱式筛掉了历史数据,半强式筛掉了公开信息,强式干脆把所有信息都筛干净了。

核心观点:如果市场是有效的,那主动管理就是白费力气。你买指数基金就行了。

弱式有效市场的实战检验

弱式有效说白了就是:技术分析没用

为什么?因为如果价格已经包含了所有历史信息,那你画什么K线、算什么均线,都是马后炮。价格变动是随机的,你没法用过去预测未来。

我在项目中遇到过一件事。有个同事花了大半年搞了一套缠论策略,回测年化收益30%+。结果我让他做了一个简单的随机性检验——把收益率序列打乱,重新跑一遍回测。你猜怎么着?收益几乎一样。

这说明什么?他的策略本质上就是在拟合噪声。

实战中怎么检验弱式有效?我一般用两种方法:

方法一:自相关检验

如果市场是弱式有效的,那今天的收益率和昨天的收益率应该没啥关系。我们算一下自相关系数就知道了。

import numpy as np
import pandas as pd
import yfinance as yf

# 获取数据
data = yf.download('000300.SS', start='2020-01-01', end='2023-12-31')
returns = data['Close'].pct_change().dropna()

# 计算自相关系数
autocorr = returns.autocorr()
print(f'一阶自相关系数: {autocorr:.4f}')

# Ljung-Box检验
from statsmodels.stats.diagnostic import acorr_ljungbox
result = acorr_ljungbox(returns, lags=[10])
print(f'Ljung-Box p值: {result["lb_pvalue"].values[0]:.4f}')

如果p值大于0.05,说明没有显著的自相关,市场符合弱式有效。我见过A股的数据,大部分时候p值都挺小的,说明短期还是有点预测性。

方法二:游程检验

这个方法更直观。我们把收益率按正负分成两串,看看正负交替的规律是不是随机的。

from statsmodels.sandbox.stats.runs import runstest_1samp

# 将收益率转为正负号
signs = np.sign(returns)
z_stat, p_value = runstest_1samp(signs, cutoff=0)
print(f'游程检验 p值: {p_value:.4f}')

实战技巧:我个人习惯把这两种方法结合起来用。自相关检验看线性关系,游程检验看非线性关系。两个都过了,才敢说市场是弱式有效的。

半强式有效市场的实战检验

半强式有效比弱式更进一步。它说:所有公开信息都已经反映在价格里了

这意味着什么?你研究财报、分析新闻、跟踪公告,都是白费功夫。因为在你看到这些信息的那一刻,价格已经调整到位了。

检验半强式有效,最经典的方法是事件研究法

举个例子:公司发布超预期的财报,股价应该怎么走?如果市场是半强式有效的,那消息一出来,股价就该一步到位。如果之后还有持续上涨,说明市场没完全消化信息。

import pandas as pd
import numpy as np
from datetime import datetime, timedelta

def event_study(prices, event_dates, window=20):
    """
    事件研究法:分析事件前后的超额收益
    """
    results = []
    
    for date in event_dates:
        # 找到事件前后的价格
        start = date - timedelta(days=window)
        end = date + timedelta(days=window)
        
        # 计算累计超额收益
        # 这里简化处理,实际要用市场模型调整
        window_data = prices.loc[start:end]
        returns = window_data.pct_change()
        cumulative_return = (1 + returns).cumprod() - 1
        
        results.append(cumulative_return)
    
    # 计算平均累计超额收益
    avg_car = pd.concat(results, axis=1).mean(axis=1)
    return avg_car

# 使用示例
# event_dates = [datetime(2023, 6, 15), datetime(2023, 9, 20)]
# car = event_study(price_data, event_dates)

注意:事件研究法有个坑——你得确定事件窗口。窗口太短可能捕捉不到反应,窗口太长又可能混入其他噪音。我曾经吃过这个亏,建议大家至少试3个不同的窗口长度。

强式有效市场的实战检验

强式有效是最极端的版本。它说:连内幕消息都没用

说实话,这个假设在现实中基本不成立。你看看那些内幕交易被抓的案例,哪个不是赚得盆满钵满?

检验强式有效,最直接的方法是看内部人交易。如果公司高管买入自家股票后,股价确实涨了,那就说明内幕消息有价值,市场不是强式有效的。

# 内部人交易分析示例
insider_trades = pd.DataFrame({
    'date': ['2023-01-15', '2023-03-20', '2023-06-10'],
    'insider': ['CEO', 'CFO', 'Director'],
    'shares_bought': [10000, 5000, 8000],
    'price_at_purchase': [50, 48, 52]
})

# 计算买入后60天的收益
for i, row in insider_trades.iterrows():
    buy_price = row['price_at_purchase']
    # 假设60天后价格为...
    price_after_60d = buy_price * 1.12  # 12%涨幅
    return_60d = (price_after_60d - buy_price) / buy_price
    print(f"{row['insider']}买入后60天收益: {return_60d:.2%}")

知识体系总览

下面这张图是我自己整理的,把三个层次的关系和检验方法串起来了:

市场有效性假说检验框架 弱式有效 历史交易信息 半强式有效 所有公开信息 强式有效 所有信息 实战检验方法 检验方法 • 自相关检验 • 游程检验 • 方差比检验 检验方法 • 事件研究法 • 日历效应检验 • 公告后漂移 检验方法 • 内部人交易分析 • 专业投资者收益 • 信息泄露检测 实战结论 A股市场:弱式无效(技术分析短期有效) 半强式部分有效(信息反应有延迟) 强式无效(内幕交易确实能赚钱)

对量化投资的启示

搞清楚了市场有效性,你就知道该怎么设计策略了:

市场状态 有效策略 无效策略
弱式无效 技术分析、动量策略、均值回归 纯随机交易
半强式无效 事件驱动、财报分析、舆情分析 纯技术分析
强式无效 内幕消息(违法!)、深度基本面 任何公开信息策略

我的建议:别纠结市场到底完不完全有效。实战中,市场往往是部分有效、部分无效的。你要做的是找到那些无效的角落,然后狠狠地赚一笔。

我记得有一次跟一个基金经理聊天,他说了一句让我印象很深的话:「市场大多数时候是有效的,但少数时候的无效,足够你吃一辈子了。」

嗯,这话糙理不糙。你想想看,如果市场永远有效,那我们量化投资这行就该失业了。正是因为市场有无效的时候,我们才有存在的价值。

最后提醒一句:别把市场有效性当成信仰。它是个工具,帮你理解市场运行规律的工具。用好了,你能少踩很多坑。

避坑指南:我曾经犯过一个错误——在弱式有效的市场上硬搞技术分析,结果亏得一塌糊涂。后来我学乖了,每次做策略之前,先跑一遍有效性检验。如果市场在这个时间尺度上是有效的,那就换个玩法。

好了,这一章就到这里。记住一句话:理解市场有效性,是你设计量化策略的第一步

专注资料整理