
本文整理自 2021 年大湾区金融数学建模竞赛 B 题的完整解题过程。题目的核心目标,是围绕湾区指数成分股,结合券商研报、市场数据与外部环境信息,构建一套能够解释股票价格波动并辅助投资决策的分析框架。围绕这一目标,全文依次设计了 二分类 Logistic 综合因子模型、事件分析模型 以及 新闻舆情因子修正模型,分别用于解决“如何刻画因子与未来收益的关系”“如何分析外部事件冲击”“如何把情绪信息纳入选股模型”这三类问题。
一、问题重述
1.1 背景
券商研报(卖方研报)是证券公司研究人员对证券及相关产品的价值或影响其市场价格的因素进行分析后所形成的研究报告。完整的券商研报包含公司经营数据、财务预测、估值结果,投资评级及风险提示等丰富信息,是投资决策的重要参考依据。
近年来,基于财务因子(市盈率,市值等)及长周期量价因子(月度反转,月度成交量等)的传统因子模型在A股市场曾获得较为稳健的超额收益。以研报特征指标为基础构建的因子量化选股模型,成为量化投资领域的前沿研究课题。
1.2 问题描述
本次研究围绕湾区指数中10支股票,结合券商研报信息与外部市场环境,完成以下四个任务:
- 问题一:选取10支湾区股票的券商研报,提取研报的特征指标。
- 问题二:建模分析研报特征指标对股票走势的影响,提出明确的投资策略。
- 问题三:研究突发事件、舆情和自然灾害等因素对10支湾区指数股票行情的影响。
- 问题四:综合券商研报与外界环境因素,修正问题二的投资策略,提出新的投资策略。
二,前置知识:核心算法原理
本章介绍后续章节中将直接引用的核心算法与关键术语。
2.1 多分类Logistic回归
算法引入原因:在因子选股问题中,股票的未来走势并非简单的线性关系,暴涨、暴跌与横盘整理三种状态之间存在复杂的非线性转换。传统线性回归无法稳定刻画这种多分类问题,而多分类Logistic回归能够在多分类场景下给出各类别的概率预测,是构建综合因子的基础算法。
模型基本原理:多分类Logistic回归通过将自变量和相应参数进行线性组合,使用概率模型计算因变量中各类别的概率。其线性预测函数为:
$$f_k(x) = \beta_{k0} + \beta_{k1}x_1 + \cdots + \beta_{kp}x_p$$
其中$\beta_{kj}$为回归系数,表示第$j$个特征对第$k$个结果的影响程度。
将对数几率化处理,可得各类别的概率:
$$P(Y=k|X) = \frac{e^{f_k(x)}}{\sum_{j=1}^{K} e^{f_j(x)}}$$
二分类特例:对于$K$个类别,以其中一个作为主类别,其余$K-1$个与主类别两两构建二分类回归。若选择第1类为主类别,则对第$l$类($l \neq 1$)与第1类的二分类可表示为:
$$\ln \frac{P(Y=l|X)}{P(Y=1|X)} = \beta_{l0} + \beta_{l1}x_1 + \cdots + \beta_{lp}x_p$$
在本研究中的应用:在因子分组策略中,将股票按未来涨跌分为三类——暴跌($y=-1$)、暴涨($y=1$)、无暴涨暴跌($y=0$),利用24个因子值作为解释变量,预测每只股票属于各类别的概率。综合因子值:
$$F(x) = \frac{1}{1 + \exp(-\beta_1 \cdot x)} - \frac{1}{1 + \exp(\beta_{-1} \cdot x)}$$
2.2 因子模型基础
因子与特征指标的关系:在量化投资中,“因子"与"特征指标"本质上是同一概念的不同表述。因子是用于解释股票收益差异的变量,通过因子值的大小可以对股票进行排序与分组。
因子模型的核心思想:因子模型假设股票的收益由若干共同因子驱动,相同因子暴露度的股票应有相似的收益表现。通过构建有效的因子,可以实现股票的预期收益排序与分组交易。
综合因子的构造:单一因子往往无法全面刻画股票的收益特征,因此需要将多个有效因子进行加权组合,构造综合因子。在本研究中,综合因子由24个研报特征指标经多分类Logistic回归压缩得到,同时叠加外部舆情因子,形成综合评分体系。
2.3 事件分析法
算法引入原因:事件分析法是一种实证研究方法,最早运用于金融领域,借助金融市场数据量化分析特定事件对公司价值的影响。该方法理论严谨、逻辑清晰、计算简单,被广泛用于研究外部冲击对股票价格的影响。
模型基本原理:事件分析法通过比较事件发生前后个股的实际收益率与"假设事件未发生"时的预期收益率之差(异常收益率),来判断事件对股价的影响方向与程度。
核心步骤:
- 事件选取:确定研究的事件及其发生时间点
- 窗口划分:将时间区间划分为估计窗(事件前120~35天)和事件窗(事件前5天至事件后40天)
- 正常收益率估算:采用市场模型(CAPM):$R_{it} = \alpha_i + \beta_i R_{mt} + \varepsilon_{it}$
- 异常收益率计算:$AR_{it} = R_{it} - \hat{R}_{it}$
- 累计异常收益率:$CAR_{cum} = \sum_{t} \bar{A}_t$
- 显著性检验:若P值小于0.05则说明外部事件对股价有显著影响
在本研究中的应用:以2018年长生生物疫苗造假事件为案例,将10支股票按申万行业分类,逐一分析各行业组合在事件窗内的累计异常收益率变化。
三、问题分析
3.1 问题一分析
问题一要求选取10支湾区股票的券商研报,并从研报中提取特征指标。运用Python爬虫在东方财富网站抓取近三年个股研报,读取研报内容并统计特征指标出现次数,结合深圳天软科技数据库获取指标具体数值与定义,作为问题二分析的重要数据来源。
3.2 问题二分析
问题二要求分析研报特征指标对股票走势的影响并提出投资策略。由于特征指标与股票走势之间存在非线性关系,线性回归无法稳定预测,因此采用机器学习方法。首先对候选因子进行有效性检验,通过相关性矩阵判断指标间相关性;然后建立多分类Logistic回归模型,以因子值和下期收益建立回归关系,构造综合因子并通过分组验证其有效性,最终形成明确的投资策略。
3.3 问题三分析
问题三要求建立模型探究外部因素对所选10支股票的影响。本文从两个角度展开研究:
- 宏观分析角度:运用事件分析法,引入特征指标分析外部因素发生时对10只股票的影响
- 行为金融学角度:从行为金融学理论出发,挖掘新闻舆情因子,构建因子模型
两个角度相辅相成,共同解释外部因素对个股的影响机制。
3.4 问题四分析
将问题三的新闻舆情因子接入问题二的因子模型,重新构建综合框架,对10支股票进行回测。通过对比加入舆情因子前后的分组效果与收益表现,验证新模型的优越性,并提出改进后的投资策略。
四、模型假设
- 研报特征指标的相关关系是稳定的。为避免使用未来数据,相关矩阵使用2013年(即期初)的研报数据。
- 研报数据与收益之间的关系是非线性的。线性关系无法稳定预测研报数据与收益之间的关系,需要构造非线性关系,机器学习可提供技术支持。
五、符号说明
| 符号 | 含义 |
|---|---|
| $R_i$ | 每只样本股的日收益率 |
| $R_m$ | 市场收益率 |
| $AR_i$ | 每只样本股的异常收益率 |
| $CAR$ | 组合平均异常收益率 |
| $CAR_{cum}$ | 组合累计平均异常收益率 |
六、模型建立与求解
6.1 问题一模型的建立与求解
6.1.1 研究对象选取
本文从湾区指数股票池中选择了10支股票作为研究对象,涵盖电子、医药生物、房地产与建筑材料等多个申万一级行业:
| 股票名称 | 股票代码 | 股票名称 | 股票代码 |
|---|---|---|---|
| 亿纬锂能 | SZ300014 | 华发股份 | SH600325 |
| 立讯精密 | SZ002475 | 塔牌集团 | SZ002233 |
| 国星光电 | SZ002449 | 美盈森 | SZ002303 |
| 顺络电子 | SZ002138 | 丽珠集团 | SZ000513 |
| 长盈精密 | SZ300115 | 国药一致 | SZ000028 |
6.1.2 数据获取:Python爬虫抓取研报
问题一的核心,是先把 10 只股票对应的研报资料系统性地收集起来。这里选择的是东方财富数据中心的个股研报页面。具体做法是先定位每只股票的研报 URL,再用 Python 爬虫抓取近三年来每只股票的历史研报 PDF。最终共抓取到 294 份研报,后续的文本清洗、分词统计和特征提取都建立在这批 PDF 资料之上。
整个数据获取流程分成三步:第一步抓取研报 PDF 链接,第二步提取 PDF 文本内容,第三步对研报文本做分词和特征频次统计。论文原文中提到的附件 text.xlsx 和 解释变量_dwq.xlsx,分别对应了研报文本整理结果和后续因子建模使用的解释变量数据。
代码功能:通过 urllib 循环请求东方财富研报列表页面,利用正则表达式提取每只股票的历史研报 PDF 下载链接,最终保存到 Excel 文件(links.xlsx)中。
import urllib
import urllib.request
import re
import pandas as pd
links = []
stocks = ['300014', '002475', '002449', '002138', '300115',
'600325', '002233', '002303', '000513', '000028']
for i in range(len(stocks)):
url = "http://data.eastmoney.com/report/" + stocks[i] + ".html"
data = urllib.request.urlopen(url).read().decode('UTF-8')
linkre = re.compile(r'\w*AP20\w*')
list1 = linkre.findall(data)
for q in list1:
pdf_url = 'https://pdf.dfcfw.com/pdf/H3_' + q + '_1.pdf'
links.append(pdf_url)
pd.DataFrame(links).to_excel("links.xlsx")
代码功能:读取研报 PDF 下载链接,依次打开每个 PDF 文件,使用 pdfminer 库提取文本内容并拼接为完整字符串,存入列表导出为 Excel(text.xlsx)。
from pdfminer.pdfparser import PDFParser, PDFDocument
from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
from pdfminer.pdfdevice import PDFDevice
from pdfminer.converter import PDFPageAggregator
from pdfminer.layout import LAParams
import pandas as pd
links_df = pd.read_excel("links.xlsx")
text_list = []
for url in links_df[0]:
try:
fp = urllib.request.urlopen(url)
parser = PDFParser(fp)
doc = PDFDocument(parser)
parser.set_document(doc)
doc.set_parser(parser)
doc.initialize()
resource = PDFResourceManager()
device = PDFPageAggregator(resource, laparams=LAParams())
interpreter = PDFPageInterpreter(resource, device)
texts = []
for page in doc.get_pages():
interpreter.process_page(page)
layout = device.get_result()
for obj in layout:
if hasattr(obj, 'get_text'):
texts.append(obj.get_text())
text_str = ''.join(texts)
text_list.append(text_str)
except:
text_list.append('')
pd.DataFrame(text_list).to_excel("text.xlsx")
代码功能:读取研报文本内容,利用 jieba 分词工具统计35个预设特征指标在每份研报中的出现频次,得到各指标的特征频率统计结果。
import jieba
import pandas as pd
import collections
with open("研报内容.txt", encoding='utf-8') as f:
data = f.read()
jieba.load_userdict("词典.txt")
seg_list = jieba.lcut(data)
counter = collections.Counter(seg_list)
# 统计35个特征指标频次
keywords = ['市场', '系统性风险', '市盈率', '市净率', '市销率', 'PEG', '净利润增长率',
'净资产增长率', '毛利率', '净资产收益率', '销售净利率', '涨跌幅', '换手率', '流通市值', '总市值', '流通股本', '总股本', '盈利预测调整']
result = [counter[k] for k in keywords]
pd.DataFrame(result).to_excel("特征频率.xlsx")
6.1.3 研报特征指标频率统计
在拿到全部研报文本之后,下一步就是统计题干示例指标在研报中的出现频次。论文把这些特征指标分为市场整体、估值因子、成长因子、盈利能力因子、动量反转因子、交投因子、规模因子、股价波动因子、分析师预测因子等多个类别,并对 35 个示例指标逐一做了频率统计。
从结果上看,不同指标在研报中的出现频率差异很大。有些指标是研报里的高频词,比如市场因子、毛利率、销售净利率、总股本;也有一些指标在样本期内几乎没有出现,比如市现率、自由流通市值、预测净利润增长率、盈利预期调整等。这个频率分布本身就能帮助我们判断,哪些指标更值得进入后续建模环节。
35 个示例指标在 294 份研报中的出现频次如下:
| 因子名称 | 出现频率 | 因子名称 | 出现频率 |
|---|---|---|---|
| 市场因子 | 2391 | 资产收益率 | 50 |
| 系统性风险 | 5 | 营业费用比例 | 0 |
| 市盈率 | 209 | 财务费用比例 | 0 |
| 市净率 | 150 | 息税前利润与营业总收入比 | 0 |
| 市销率 | 27 | 前期涨跌幅 | 425 |
| 市现率 | 0 | 前期换手率 | 70 |
| 企业价值倍数 | 0 | 量比 | 0 |
| PEG | 58 | 流通市值 | 165 |
| 营业收入增长率 | 128 | 总市值 | 322 |
| 营业利润增长率 | 59 | 自由流通市值 | 0 |
| 净利润增长率 | 171 | 流通股本 | 131 |
| 每股收益增长率 | 0 | 总股本 | 389 |
| 净资产增长率 | 44 | 前期股价振幅 | 0 |
| 股东权益增长率 | 3 | 日收益率标准差 | 0 |
| 经营现金流增长率 | 0 | 预测净利润增长率 | 0 |
| 销售净利率 | 671 | 预测主营业务增长率 | 0 |
| 毛利率 | 1662 | 盈利预期调整 | 0 |
| 净资产收益率 | 170 |
6.1.4 特征指标定义与筛选
在频率统计之后,论文没有直接把所有指标一股脑拿去建模,而是先对“频次大于 0”的指标做进一步分析。这里一方面借助深圳天软科技数据库读取指标的具体定义,另一方面结合金融学中的常用解释框架,把这些指标放回到各自所属的因子类别中理解。
从具体定义来看,这些指标可以概括为下面几类:
市场因子
- 市场因子:沪深 300 指数成分股在 t-1 月末到 t 月末的总股本加权涨幅。
- 系统性风险:对个股与沪深 300 指数在 t-12 月末到 t 月末的对数收益率序列作一元线性回归,斜率即为系统性风险值。
估值因子
- 市盈率:t 月末总市值除以最近 12 个月净利润。为了控制指标值域,对该指标取倒数处理。
- 市净率:t 月末市净率(最近 12 个月,按公布日)。为了控制指标值域,对该指标取倒数处理。
- 市销率:t 月末个股市销率(最近 12 个月,按公布日)。为了控制指标值域,对该指标取倒数处理。
- PEG:t 月末个股 PEG(最近 12 个月)。
成长因子
- 营业收入增长率:取 t 月末最新财报中的营业收入增长率。
- 营业利润增长率:取 t 月末最新财报中的营业利润增长率。
- 净利润增长率:取 t 月末最新财报中的净利润增长率。
- 净资产增长率:取 t 月末最新财报中的净资产增长率。
- 股东权益增长率:取 t 月末最新财报中的股东权益增长率。
盈利能力因子
- 销售净利率:取 t 月末最新财报中的销售净利率。
- 毛利率:取 t 月末最新财报中的毛利率。
- 净资产收益率:取 t 月末最新财报中的净资产收益率。
- 资产收益率:取 t 月末总资产收益率,计算公式为总资产收益率(%)=[净利润+财务费用*(1-税率)]/总资产*100。
交易因子
- 前期涨跌幅(1 月):t 月末与 1 个月前时点的股价涨跌幅度。
- 前期涨跌幅(3 月):t 月末与 3 个月前时点的股价涨跌幅度。
- 前期涨跌幅(6 月):t 月末与 6 个月前时点的股价涨跌幅度。
- 前期换手率(1 月):t 月末前 1 个月期间内市场中股票转手买卖的频率。
- 前期换手率(3 月):t 月末前 3 个月期间内市场中股票转手买卖的频率。
规模因子
- 流通市值:t 月末个股的流通市值。
- 总市值:t 月末个股的总市值。
- 流通股本:t 月末个股的流通股本。
- 总股本:t 月末个股的总股本。
在完成定义梳理之后,我们进一步从深圳天软科技数据库中读取这些因子的时间序列具体值。一方面,这让特征指标不再只是研报里的“关键词”,而是真正落成可以用于后续回归建模的结构化变量;另一方面,也为问题二中的因子模型提供了完整的解释变量数据来源。
最终筛选出的有效因子按论文口径共 24 个,并将其作为问题二因子模型的核心输入。这里的计数方式是把前期涨跌幅按 1 月、3 月、6 月拆成 3 个指标,把前期换手率按 1 月、3 月拆成 2 个指标。
6.2 问题二模型的建立与求解
6.2.1 候选因子与数据预处理
在进入问题二之前,先交代一下后面会反复用到的方法。本文采用的是多类别 Logistic 回归。它可以理解为对传统逻辑回归的一次扩展,用来预测一个样本落在不同类别中的概率。
从这里开始,文章会正式转入“因子构建”的视角。也就是说,问题一中提取出来的研报特征指标,在这一部分都统一看作“因子”。接下来的任务,就是先检查这些因子是否有效,再判断它们之间是否存在过强的相关关系,并对冗余因子进行合并或筛选。
本文使用的是 2013-2021 年 10 只股票的月频数据。模型的核心输入包括两部分:一是下期(t+1 月末)收益,二是当期(t 月末)的 24 个因子值。对于数值过大的变量,我们做了取倒数或取对数处理,以便把变量控制在相对稳定的数值范围内。
6.2.2 因子筛选与相关性检验
在做因子筛选时,我们先构造了相关性矩阵。这里有一个前提假设:同一组特征指标之间的相关关系在样本期内是稳定的。为了避免“未来函数”问题,相关矩阵使用的是 2013 年 1 月,也就是回测期初的数据。
相关系数计算公式为:
$$ r(X,Y) = \frac{\mathrm{Cov}(X,Y)}{\sqrt{\mathrm{Var}[X]\mathrm{Var}[Y]}} $$

我们的判断标准很直接:如果 24 个因子中任意两个因子的相关系数绝对值大于 0.8,就说明它们之间可能存在较强的多重共线性,需要进一步合并。最终结果是,表中所有因子两两之间的相关系数绝对值都小于 0.8,因此全部因子都被保留下来,并继续代入后续的机器学习模型。
6.2.3 因子模型框架构建
为了把“当期因子”和“下期收益”之间的关系真正建起来,我们参考了 Probability of Price Crashes, Rational Speculative Bubbles, and the Cross Section of Stock Returns 这篇文章的思路来构造 Logistic 模型。
对应到问题二的建模中,暴跌和暴涨两类结果的概率可以写成:
$$ \Pr_t\left(Y_{i,t,t+12}=-1\right)= \frac{\exp\left(\alpha_{-1}+\beta_{-1}X_{i,t}\right)} {1+\exp\left(\alpha_{-1}+\beta_{-1}X_{i,t}\right)+\exp\left(\alpha_{1}+\beta_{1}X_{i,t}\right)} $$
$$ \Pr_t\left(Y_{i,t,t+12}=1\right)= \frac{\exp\left(\alpha_{1}+\beta_{1}X_{i,t}\right)} {1+\exp\left(\alpha_{-1}+\beta_{-1}X_{i,t}\right)+\exp\left(\alpha_{1}+\beta_{1}X_{i,t}\right)} $$
参考文献里的做法,是把股票未来可能出现的状态划分为三类:暴跌、暴涨、非暴跌暴涨,分别记作 -1、1、0;同时把当期因子作为解释变量,通过 Logit 模型去解决这个多分类问题,并预测股票未来的暴跌概率。本文沿用了这个思路,构造自己的因子 Logit 模型。
在被解释变量的定义上,我们也给了非常明确的规则:如果未来区间内跌幅超过 50%,记作暴跌,用 -1 表示;如果涨幅超过 100%,记作暴涨,用 1 表示;其余情况则记作无暴跌暴涨,用 0 表示。
模型的训练方式是滚动进行的。具体来说,在每个 t 月末,取 t 之前的全部月频数据做一次多分类 Logistic 回归。按照上面的标签定义,暴跌和暴涨分别作为不同结果类别,再据此计算回归系数。
多类别 Logistic 回归的核心思想,可以概括为一句话:先把自变量和参数做线性组合,再用概率模型计算样本落入不同结果类别的概率。这里先简要介绍这个方法,再把它真正应用到 10 只股票的月频截面数据上,目的是建立“当期因子值”和“下期收益状态”之间的非线性关系。
下面这段代码对应的就是回归系数的求解过程:
import pandas as pd
import pylab as pl
import numpy as np
from sklearn import datasets
import warnings
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression,LogisticRegression,Ridge,RidgeCV,Lasso, LassoCV
from sklearn.model_selection import train_test_split,GridSearchCV,cross_val_score,cross_validate
from sklearn import metrics as mt
#warnings.filterwarnings('ignore')
# 使文字可以展示
plt.rcParams['font.sans-serif'] = ['SimHei']
# 使负号可以展示
plt.rcParams['axes.unicode_minus'] = False
print('开始')
data_ori = pd.read_excel("解释变量_dwq.xlsx")
data_ori=pd.DataFrame(data_ori)
time = data_ori.iloc[:, -1]
time=time.drop_duplicates()
#print(time)
time1=time.tolist()
#print(time1)
length=len(time1)
#print(length)
list1=[]
n=12
while n < length-12 :
print(n)
t=time1[n]
#print(t)
data=data_ori[(data_ori.时间<=t)]
#print(data)
data_01=data;
data_02=data;
data_01=data_01[(data_01.mark!=-1)]
data_02=data_02[(data_02.mark!=1)]
#print(data)
#print(data_01)
#print(data_02)
data1 = data_01[['mark','市场因子','系统性风险','市盈率','市净率','市销率','PEG',
'"营业利润增长率(%)"','股东权益增长率(%)','销售净利率(%)','销售毛利率(%)','净资产收益率(%)',
'前期涨跌幅1月','前期涨跌幅6月','前期换手率1月','前期换手率3月','流通市值',"'流通股本'"]]
X = data1.iloc[:, 1:]
y = data1.iloc[:, 0]
model = LogisticRegression()
model.fit(X, y.astype('int'))
coef1 = model.coef_ # 回归系数
coef1_icp=model.intercept_
#coef_regression1 = pd.Series(index=['Intercept'] + X.columns.tolist(), data=[model.intercept_[0]] + coef.tolist()[0])
#print(coef1)
a1=coef1[0]
b1=coef1_icp[0]
a1=np.append(a1,b1)
data2 = data_02[['mark','市场因子','系统性风险','市盈率','市净率','市销率','PEG',
'"营业利润增长率(%)"','股东权益增长率(%)','销售净利率(%)','销售毛利率(%)','净资产收益率(%)',
'前期涨跌幅1月','前期涨跌幅6月','前期换手率1月','前期换手率3月','流通市值',"'流通股本'"]]
X2 = data2.iloc[:, 1:]
y2 = data2.iloc[:, 0]
mode2 = LogisticRegression()
mode2.fit(X2, y2.astype('int'))
coef2 = mode2.coef_ # 回归系数
coef2_icp=mode2.intercept_
a2=coef2[0]
b2=coef2_icp[0]
a2=np.append(a2,b2)
a=np.hstack((a1,a2))
an=a.tolist()
an.append(t)
list1.append(an)
#print(an)
n+=1
#for i in tqdm(range(100)):
#sleep(0.01)
#pass
#print(list1)
dt=pd.DataFrame(list1)
dt.to_excel(r'ab.xlsx',sheet_name='测试')
6.2.4 综合因子构造
在拿到逻辑回归的系数之后,下一步就是把它和 t 月的解释变量值结合起来,构造综合因子。这里把这个综合因子理解为暴跌概率,也就是一种可以对预期收益进行排序的指标。
设 $t-12$ 月的系数为 $\alpha_1$、$\alpha_{-1}$、$\beta_1$、$\beta_{-1}$,$t$ 月解释变量为 $X_1$。得到暴跌概率的计算公式如下:
$$ P_{\text{暴跌}}= \frac{\exp\left(\beta_{-1}^{T}X_1+\alpha_{-1}\right)} {\exp\left(\beta_{-1}^{T}X_1+\alpha_{-1}\right)+\exp\left(\beta_{1}^{T}X_1+\alpha_{1}\right)+1} $$
这一步的核心含义并不复杂:通过回归系数和当期因子值的组合,把原本分散的多个研报特征压缩成一个可以直接排序的核心指标。这里构造出的综合因子,本质上对应的是暴跌概率,也可以理解为对预期收益进行有序排列的结果,再据此比较不同股票未来收益的差异。
6.2.5 投资策略设计与回测验证
有了综合因子之后,下一步就是先把投资策略明确下来。这里采用的是月频调仓思路:在 2013-2021 年的每个月末进行一次调仓,并按照综合因子值把 10 支股票分成三组,其中第一组综合因子值最低,预期收益最高;最后一组综合因子值最高,预期收益最低。
在每个 t 月末,具体执行步骤如下:
- 取得 t 月之前的所有被解释变量(y=1、-1 或 0)的值,以及所有解释变量(24 个因子的值)。
- 对以上数据进行多分类逻辑回归,得到回归系数。
- 计算综合因子值。
- 每个个股通过综合因子值进行排序,做多综合因子低的前 1/3 股票,可以实现收益最大化。
其中第 3 步使用的综合因子计算公式为:
$$ P_{\text{暴跌}}= \frac{\exp\left(\beta_{-1}^{T}X_1+\alpha_{-1}\right)} {\exp\left(\beta_{-1}^{T}X_1+\alpha_{-1}\right)+\exp\left(\beta_{1}^{T}X_1+\alpha_{1}\right)+1} $$
在策略确定之后,再对这套方法进行单因子回测。回测结果如下表所示:
| 分组 | 回测期末累计收益 | 年化收益率 | 相对沪深300表现 |
|---|---|---|---|
| 第一组 | 1517% 以上 | 41.6% | 明显跑赢基准 |
| 第二组 | 约 994% | 34.9% | 明显跑赢基准 |
| 第三组 | 约 25% | 2.83% | 明显弱于基准 |

最后可以看到,构建出的综合因子是有效的,第一、二、三组之间的分组效果明显。这说明按照综合因子排序并进行月频调仓之后,该投资策略在这 10 只股票上取得了较好的收益表现。
6.3 问题三模型的建立与求解
6.3.1 外部因素对股价的影响机理
在实际股市交易过程中,股票走势并不总是按照既有预期发展。原因在于,市场中会不断出现各种外部冲击,这些事件会对个股和行业产生不同程度的影响。虽然很多外部因素本身无法被提前预判,但我们仍然可以通过研究过往事件发生后的市场反应,总结其中的规律,进而分析外部因素与股价波动之间的联系。
在这篇研究里,关注的外部因素主要包括突发事件、新闻舆情和自然灾害等。从宏观分析的角度,可以用事件分析法来研究外部冲击发生后股票价格的变化;从行为金融学的角度,则可以借助新闻舆情指数来刻画投资者关注度和情绪变化,进一步解释外部因素如何影响股票市场。
外部因素影响股价的逻辑并不复杂。一个突发事件发生后,会迅速吸引投资者关注,并改变市场情绪。投资者依据已有信息做出判断与决策,如果大量投资者在短时间内做出相似反应,股价就会出现明显波动。也正因为如此,新闻舆情指数既能反映市场关注程度,也能反映市场情绪方向,从而成为连接外部事件与股票波动的重要变量。
基于这一思路,问题三主要从两个方向展开:一是基于事件分析法构建模型,研究特定外部事件对股票组合收益的冲击;二是围绕新闻舆情因子构建模型,从情绪与关注度角度解释外部因素对股价的影响。这两种方法从不同角度切入,但目标是一致的,都是为了更系统地理解外部因素与股票价格波动之间的关系。
6.3.2 基于事件分析法的模型建立
在问题三中,首先采用的是事件分析法。事件分析法最早运用于金融领域,核心思想是比较事件发生前后样本股票的实际收益和“假设事件未发生”时的正常收益,从而判断该事件是否对股价造成了显著影响。
事件分析法的建模步骤一共包括 12 个部分,核心可以整理为以下几步:
- 事件选取:选取 2013-2021 年期间发生的、与行业或个股主体有关的重要事件。
- 事件日确定:确定市场接受信息的时间点,并据此划分估计窗和事件窗。估计窗用于估计正常收益率,通常选择事件发生前 120d-35d;事件窗则根据事件可能持续的影响范围灵活确定。
- 研究样本选择:选取可能受事件影响的股票样本。本文对应的研究样本仍然是前面选取的 10 只股票,同时再按申万一级行业分类,形成行业组合,便于后续比较不同行业对外部事件的反应差异。
- 正常收益率估计:在估计窗内用市场模型计算股票的正常收益率。这里采用的是市场模型而不是常数均值调整模型或市场调整模型,原因是市场模型解释更全面,也更符合金融研究中的通用做法。
- 异常收益率计算:在得到正常收益率之后,进一步计算事件窗内的异常收益率、组合平均异常收益率和累计平均异常收益率,以衡量事件冲击对股票组合带来的额外影响。
- 显著性检验:对累计异常收益率序列做均值 T 检验。如果 P 值小于 0.05,就说明在 5% 的显著性水平下,事件对样本组合股价波动具有显著影响。
这一部分还需要用到若干关键公式。首先,个股在事件窗内的日收益率可以表示为:
$$ R_{it} = \frac{P_{it} - P_{i,t-1}}{P_{i,t-1}} $$
市场收益率可写为:
$$ R_{mt} = \frac{I_t - I_{t-1}}{I_{t-1}} $$
在正常收益率估计中,采用的市场模型为:
$$ R_{it} = \alpha_i + \beta_i R_{mt} + \varepsilon_{it} $$
异常收益率定义为实际收益率与正常收益率之差:
$$ AR_{it} = R_{it} - \hat{R}_{it} $$
组合平均异常收益率为:
累计平均异常收益率为:
$$ CAR(t_1,t_2) = \sum_{t=t_1}^{t_2} \overline{AR}_t $$
通过这组公式,就可以把某个事件对单只股票和行业组合的影响量化出来,再进一步检验这一影响是否显著。
6.3.3 实证设计与模型求解
在实证设计部分,这里从常见外部因素中选取了一个典型案例来展示事件分析法的应用过程。首先,对前面选取的 10 只股票按申万一级行业进行归类。结果显示,这 10 只股票中有一半属于电子行业,2 只属于医药生物行业,其余分别属于房地产、建筑材料和轻工制造行业。
对应的行业分类如下表所示:
| 股票名称 | 申万一级行业分类 | 股票名称 | 申万一级行业分类 |
|---|---|---|---|
| 亿纬锂能 | 申万电子 | 华发股份 | 申万房地产 |
| 立讯精密 | 申万电子 | 塔牌集团 | 申万建筑材料 |
| 国星光电 | 申万电子 | 美盈森 | 申万轻工制造 |
| 顺络电子 | 申万电子 | 丽珠集团 | 申万医药生物 |
| 长盈精密 | 申万电子 | 国药一致 | 申万医药生物 |
基于这一行业结构,在案例分析中重点选择了 2018 年狂犬疫苗造假事件。选择这个事件的原因很明确:它以医药行业为起点,但外溢影响较强,更适合用来观察事件分析法在行业冲击研究中的效果。
在具体设定上,这里将 2018 年 7 月 16 日作为事件发生日,并将事件发生前 120 天设为估计窗口,即 2018 年 2 月 26 日至 2018 年 7 月 9 日;将事件发生前 5 天至事件发生后 40 天设为事件窗口。数据来源仍然是深圳天软科技数据库。由于湾区指数成立于 2019 年,不能直接作为市场收益率基准,因此这里选取沪深 300 指数作为市场收益率参考。
在行业划分上,进一步把 10 只股票归并为三类:电子信息类、医药类和建筑类。之后,将每一类股票的数据代入前述事件分析模型,计算各组合在事件窗内的正常收益率、异常收益率、组合平均异常收益率和累计平均异常收益率,并据此观察不同组合在事件冲击下的反应程度。
按这一口径做二次分类后,股票组合可以整理为:
| 股票名称 | 行业分类 | 股票名称 | 行业分类 |
|---|---|---|---|
| 亿纬锂能 | 电子信息类 | 华发股份 | 建筑类 |
| 立讯精密 | 电子信息类 | 塔牌集团 | 建筑类 |
| 国星光电 | 电子信息类 | 美盈森 | 建筑类 |
| 顺络电子 | 电子信息类 | 丽珠集团 | 医药类 |
| 长盈精密 | 电子信息类 | 国药一致 | 医药类 |
在具体案例分析中,可以把这一部分继续拆成四步:
- 确定事件发生日:以 2018 年 7 月 16 日播送的长生生物疫苗造假事件作为研究起点。
- 确定事件窗口:设定事件发生前 120 天为估计窗口,事件发生前 5 天至发生后 40 天为事件窗口。
- 确定数据来源:从深圳天软科技数据库提取个股在估计窗口和事件窗口内的日收盘价,并以沪深 300 指数作为市场收益率基准。
- 代入模型求解:将不同组合股票的数据代入事件分析模型,计算正常收益率、异常收益率、组合平均异常收益率和累计平均异常收益率。
将三类股票组合的实证结果汇总后,可以整理为下表:
| 股票组合 | T-statistic | P-value | 显著性结论 | 结果解读 |
|---|---|---|---|---|
| 医药类 | 8.085680088 | 约 0.00002 | 在 95% 置信水平下显著 | 突发事件发生后,医药类组合收益率先下降,随后随着事件逐步消化而回升并趋于平稳。 |
| 建筑类 | 11.478369766 | 约 0.00003 | 在 95% 置信水平下显著 | 建筑类组合在医药事件发生后也出现收益反转下跌,随后重新逐步抬升,说明该板块同样受到事件与大盘的共同影响。 |
| 电子信息类 | -2.062110627 | 约 0.045133004 | 在 95% 置信水平下显著 | 电子类组合也受到医药行业冲击,收益先下跌,之后出现一段不稳定震荡,最后逐渐趋于平稳。 |
从这三组结果可以看到,突发事件对不同板块都会在短期内造成明显冲击,但后续消化过程存在差异。医药类作为事件源头受到的影响最直接,建筑类和电子类则更多体现为外溢效应下的联动波动。共性在于,各组合在事件发生后都经历了收益振荡,并最终逐步走向平稳。
这一部分的意义在于,它把问题三从“理论上可以分析外部因素”推进到了“可以用具体案例量化验证外部因素影响”的层面。也就是说,事件分析法不仅给出了研究框架,也为后续比较不同行业组合的受冲击程度提供了可操作的数据路径。
6.3.4 基于新闻舆情因子的模型建立与求解
在事件分析法之外,问题三还从行为金融学的角度引入了新闻舆情因子。这里的核心想法是:如果外部事件会显著影响投资者关注度和情绪,那么新闻标题本身就可以被转化为一个可量化的解释变量,用来刻画市场对个股的情绪变化。
新闻舆情因子的构建过程一共分成 6 个步骤:
- 获取数据:以月为单位,从东方财富网爬取 10 只股票自 2021 年 1 月开始的新闻标题数据,得到新闻标题样本集。
- 数据预处理:对样本集中的新闻标题使用 jieba 分词,将文本拆分后用空格连接;再借助第三方停用词表处理中文停用词;最后通过 CountVectorizer 将中文词语向量化。
- 构造训练集与测试集:将样本集拆分为训练集和测试集,并对部分训练集新闻标题进行人工评分。评分规则如下:
1表示判断看涨,0表示无法明显判断,-1表示判断看跌。 - 建立分类模型:在人工打分基础上,先对文本做特征向量化,再导入朴素贝叶斯分类器,对训练集其余新闻标题进行自动打分。
- 验证预测准确率:将未特征向量化的数据输入模型,检验机器学习预测的准确率。
- 构造舆情因子:对每只股票在每个月内全部新闻标题的得分做算术平均,得到该股票在该月的新闻舆情分数,并将其定义为新闻舆情指标,也就是后续使用的“舆情因子”。
基于这一流程,就可以为每只股票、每个月都构造出一个舆情因子。由于舆情因子具有较强的时效性,它不适合继续沿用问题二中“用一年后的暴跌暴涨结果与一年前因子值回归”的同一逻辑。因此,这里并没有重新构造一套完全独立的模型,而是选择对问题二中的综合因子做修正。
具体做法是,先计算 10 只股票每个月的平均舆情因子,再检验问题二中 α1、α-1 与舆情因子之间的相关关系,并通过 R² 判断相关性强弱。检验结果是:α1 与舆情因子的 R² 为 0.4432,α-1 与舆情因子的 R² 为 0.0859。这说明舆情因子与 α1 之间存在较强联系,而与 α-1 的关系并不显著。

基于这一结果,这里将
$$ \alpha_1 = -0.0653x - 0.013 $$
代入问题二中的综合因子模型。在每次计算综合因子时,变量 x 都采用个股当期的舆情因子值,从而让综合因子不仅反映个股的内部基本面信息,也能反映外部情绪变化带来的冲击。
从经济含义上看,这个修正项的作用也比较直观:当个股舆情由负转正时,舆情因子值 x 上升,模型中的相关项上升,个股暴跌概率下降;当个股舆情由正转负时,舆情因子值下降,个股暴跌概率上升。也就是说,舆情因子本质上是在给问题二中的综合因子加入一层“市场情绪修正”。
通过这一处理,问题三中的新闻舆情因子不再只是一个辅助观察指标,而是被真正并入到后续的综合因子建模框架中,为问题四进一步融合内外部因素打下基础。
6.4 问题四模型的建立与求解
6.4.1 改进后投资策略的重新设计
基于新的综合因子,问题四中的投资策略也需要重新表述。在每个 t 月末,调仓过程可以概括为以下几步:
步骤一:取得 t 月之前所有被解释变量(y=1、-1 或 0)的值,以及所有解释变量(24 个因子的值)。
步骤二:对以上数据进行多分类逻辑回归,得到两组回归系数。
步骤三:获取每个月的舆情因子值,并计算所有个股舆情因子值的算术平均,再与 α 做最小二乘拟合,建立 α 与个股舆情因子值 x 之间的关系。
其中,拟合得到的关系式为:
$$ \alpha_1 = -0.0653x - 0.013 $$
步骤四:将上式代入综合因子值中,得到新的综合因子。
步骤五:对所有个股按照综合因子值进行排序,做多综合因子最低的前 1/3 股票,以实现收益最大化。
相比问题二,这套策略的实质变化就在于:每月调仓时不再只使用内部因子,而是把当期舆情因子也纳入综合因子的计算过程,使得选股结果能够同时反映公司内在特征和外部情绪变化。
6.4.2 新旧模型回测对比与改进效果分析
在完成模型改造之后,首先需要用统一口径比较新旧两套模型的选股效果。具体做法是:保留问题二中原有的分组回测框架,仍然按照月频调仓、按综合因子排序分组,再分别计算旧综合因子和加入舆情因子后的新综合因子在同一时间区间内的收益曲线与分组表现。这样处理的目的,是把“是否引入舆情因子”作为唯一变量,从而更清楚地识别模型改进带来的变化。


从回测结果来看,新模型的整体表现优于旧模型,主要体现在以下几个方面:
- 整体收益表现更好:在 2021 年市场整体调整的背景下,旧综合因子分组下三组股票都出现了较明显回撤,其中第一组回撤尤为突出;相比之下,新模型的分组表现更稳健。
- 分组区分度更清晰:在 2021 年 2 月到 9 月这段区间,如果不引入舆情因子,第一组和第二组的收益曲线会长期缠绕在一起,难以形成有效区分;加入舆情因子后,第一组股票在大部分时间里都明显跑赢第二组。
- 层次稳定性更强:新模型下不同组别之间的收益排序更加稳定,说明新的综合因子能够更清楚地识别股票间的相对强弱。
从改进效果分析来看,舆情因子的价值主要集中在两点:
- 提升因子有效性:舆情因子增强了综合因子对股票未来表现的区分能力,使得分组结果更有辨识度。
- 增强逆风环境适应性:在股池整体下跌时,新模型对第一组回撤的控制更有效,说明它对不利市场环境的适应能力更强。
因此,问题四的结论可以概括为:把新闻舆情因子并入问题二中的综合因子模型之后,新模型的回测效果整体优于旧模型,第一层次股票的收益表现也有所改善。这说明新模型在解释股票价格波动时,能够同时吸收内部基本面信息与外部情绪信息,因而具备更强的实用价值。
七、模型评价与展望
7.1 模型优势
综合全文的建模与实证结果来看,这套因子选股研究的主要优势体现在以下几个方面:
- 因子综合框架较完整:模型并没有只依赖单一类型的信息,而是把研报特征、财务与市场因子、外部事件以及新闻舆情因子放在同一研究框架中统一考察,能够同时覆盖股票价格波动中的内生性因素与外生性因素。
- 机器学习方法适合处理复杂关系:相比传统线性方法,多分类 Logistic 回归能够更好地刻画因子值与未来收益状态之间的非线性联系,在保留统计解释性的同时,也提升了模型对复杂市场关系的刻画能力。
- 因子筛选过程具有一定严谨性:从研报文本频次统计、深圳天软科技数据库因子映射、相关性检验,到后续综合因子构造,整套流程层次清晰,避免了简单堆砌变量带来的冗余问题。
- 事件分析法增强了解释能力:在因子收益预测之外,事件分析法为“外部冲击如何影响股价”提供了相对清晰的量化路径,使模型不仅能做收益分组,也能从机制层面解释特定事件对行业和股票组合的影响。
- 舆情因子改造提升了实用性:问题四在原有模型基础上进一步引入新闻舆情因子,使得模型在面对市场情绪变化时具备更高敏感度,也让最终策略更贴近真实投资环境中的信息传导过程。
7.2 模型局限
尽管模型在样本内展示出了较好的分组效果,但从研究设计和实际应用角度看,仍然存在一些不能忽视的局限:
- 样本股票数量偏少:全文研究对象主要围绕 10 只湾区指数成分股展开,这样的样本规模更适合做方法验证,但对更广泛市场环境的代表性仍然有限,模型的泛化能力需要在更大股票池中继续检验。
- 回测区间具有阶段性特征:样本期内市场风格、行业轮动以及外部事件冲击都具有较强阶段性,因此当前回测结果更多说明模型在特定时期内有效,还不能直接等同于长期稳定有效。
- 舆情因子存在较强时效性:新闻标题和市场情绪变化往往传播很快、衰减也很快,这意味着舆情因子在不同频率下可能具有不同效果。若处理不当,容易出现信号滞后或噪声放大的问题。
- 因子融合方式仍较为线性:虽然问题四已经把舆情因子纳入综合框架,但当前融合逻辑仍偏向在既有模型上做修正,尚未充分挖掘不同类型因子之间更复杂的交互关系。
- 实盘约束尚未完全纳入:本文回测主要关注收益表现和分组效果,对交易成本、调仓冲击、流动性限制等真实交易条件考虑较少,因此策略从研究结论走向实盘应用时,还需要进一步校准。
7.3 改进方向
基于上述局限,后续如果继续完善这套研究框架,可以从以下几个方向推进:
- 扩展外部数据维度:在新闻舆情之外,进一步引入宏观经济指标、行业景气度、政策事件、资金流向等外部变量,构建更完整的外生信息刻画体系。
- 优化因子融合机制:不再局限于对原综合因子做线性修正,而是尝试建立分层融合或动态加权机制,让基本面因子、市场因子与情绪因子在不同市场环境下自动调整权重。
- 尝试更丰富的机器学习算法:在保留 Logistic 回归可解释性的基础上,可以进一步尝试随机森林、梯度提升树、XGBoost 等集成方法,对比不同模型在稳定性、解释性与预测能力之间的差异。
- 扩大样本范围做稳健性检验:把研究对象从 10 只股票扩展到更大规模的股票池,并拉长回测时间区间,考察模型在不同市场状态、不同板块和不同风格环境下的表现是否仍然成立。
- 补充真实交易层面的验证:在后续研究中加入交易成本、滑点、换手率约束和组合容量分析,使策略结果从“学术上有效”进一步走向“实务上可执行”。
总体来看,本文所构建的因子模型已经验证了“研报特征指标 + 外部舆情因子”这一研究思路的可行性,也为后续把文本挖掘、事件冲击分析和量化选股进一步结合,提供了一个可以继续拓展的基础框架。
八、参考文献
[1] Probability of Price Crashes, Rational Speculative Bubbles, and the Cross Section of Stock Returns. Journal of Financial Economics.
[2] 深圳天软科技数据库技术文档.
[3] 申万行业分类标准.
附录:各问题核心代码见论文附件。