股价日内模式中蕴藏的选股因子

本文深入研究股价日内模式,发现上午的价格行为蕴含更多信息,据此构建统计量 stat 和 APM 因子。APM 因子通过消除与动量因子的相关性,展现出较强的选股能力。分层回测和多空组合显示,APM 因子能够有效提升投资组合的收益,特别是在进行市值行业中性化处理后,收益能力和风险控制表现更优。

研究目的

 

本文参考方正证券研报《凤鸣朝阳:股价日内模式中蕴藏的选股因子》,根据研报分析,由于隔夜时段的交易暂停,每个交易日开盘后,市场累积的大量私有信息,将通过交易迅速得到释放,知情交易概率在日内呈现快速下降的态势。上午知情交易的成分较高,因而个股的价格行为个性较足,相关性较低;下午知情交易逐渐退去,因而个股的价格行为更多呈现了随波逐流的状态,越发向市场平均靠拢。

 

根据此结论,本文对研报里面的结果进行了分析,并对股票价格日内模式进行了研究,从其中提取出 alpha 因子,从而实现对股票未来收益的预测,为 alpha 因子在日内高频数据中的挖掘提供了一定思路。

 

研究内容

 

 

(1)研究在日内高频数据中挖掘 alpha 因子,通过研究发现日内上午的价格比下午的价格行为隐藏着更丰富的信息,通过测算股价行为上午与下午的差异,构建统计量 stat。

 

(2)考虑到构建的统计量 stat 与股票过去 20 日收益率具有强相关性,为了避免其影响,采用回归的方法,计算残差,并将其命名为 APM 因子,并通过分层回测、多空组合等多种方式分析因子的有效性。

 

(3)进一步分析 APM 因子与市值之间的关系,然后计算市值行业中性化处理后的因子数据,并根据其进行分层回测、多空组合,从而分析因子的有效性。

 

 

研究结论

 

(1)在股价日内模式的研究中发现:交易日上午的价格行为,较之于下午的价格行为,蕴藏了更多可用于选股的信息量。知情交易者更加倾向于在每日上午进行交易,因此上午的股价涨跌更加能够反映知情交易者的多空态度。

 

(2)本文以全市场股票池为标的,剔除停牌股、ST 股以及上市不足 3 个月的股票,通过测算股价行为上午与下午的差异,构建了用于选股的 APM 因子。因子值越小,表示知情交易者越倾向于做多; 因子值越大,则表示知情交易者越倾向于做空。

 

(3)根据 APM 因子对所有 A 股进行排序并等分五组,多空对冲组合的多空对冲净值的收益指标值,年化收益为 9.89%,期间最大回撤为 5.34%,夏普比率为 0.98,年化收益波动率为 5.98%,显示出较强的选股能力。

 

(4)考虑到 APM 因子与市值因子具有较强的相关性,因此考虑通过多元线性回归的方式,进行行业市值中性化处理,通过处理后的数据进行选股,对所有 A 股进行排序并等分五组,多空对冲组合的年化收益为 10.99%,期间最大回撤为 4.26%,夏普比率为 1.52,年化收益波动率为 4.59%,与原始 APM 因子相比不仅收益能力更强,且对风险的控制做的更好。

 

 

研究耗时

 

(1)数据准备部分:大约需要 1.5h,主要出现在数据采集部分,为了避免程序耗时过长,已将数据提前运行出来,下载地址:https://pan.baidu.com/s/1zuyqM_PABP4M5AvkOF1hfQ

 

(2)模型测试部分:包含 APM 因子的 5 层分层回测及多空组合,经过市值行业中性化后的因子的 5 层分层回测及多空组合,大约需要 30min,主要回测组合较多,且每个组合每次调仓股票数量较多,导致运行速度较慢。

 

 

数据准备

1.1 日期列表获取

 

在每个月的月末对因子数据进行提取,因此需要对每个月的月末日期进行统计。

 

输入参数分别为 peroid、start_date 和 end_date,其中peroid进行周期选择,可选周期为周(W)、月(M)和季(Q),start_date和end_date分别为开始日期和结束日期。

 

函数返回值为对应的月末日期。本文选取开始日期为 2013.1.1,结束日期为 2017.1.1。

 

1.2 股票列表获取

 

股票池: 全 A 股

股票筛选:剔除 ST 股票,剔除上市 3 个月内的股票,每只股票视作一个样本

以 HS300 为例,取 2016-08-31 当天的股票成分股

 <

<think>我们正在处理一个多因子选股策略的实现问题。根据用户提供的引用,特别是引用[1]中提到的因子研究体系,以及引用[2][3][4]中关于APM因子的构建和分析,我们可以构建一个多因子选股策略。 在ptrade中实现多因子选股策略通常包括以下步骤: 1. 数据准备:获取股票池,并获取每个因子的数据。 2. 因子处理:对因子进行标准化、中性化(如行业市值中性化)等处理。 3. 因子合成:将多个因子合成为一个综合因子(可选)。 4. 股票排序:根据综合因子(或单个因子)对股票进行排序。 5. 组合构建:选择排名靠前的股票构建投资组合。 6. 调仓:定期执行上述步骤,调整持仓。 下面我们以两个因子(例如:APM因子和动量因子)为例,展示如何在ptrade中编写多因子选股策略。 注意:以下代码示例基于ptrade的API,假设我们使用日线数据,每月调仓一次。 步骤: 1. 初始化:设置股票池、因子、调仓频率等。 2. 定时任务:在调仓日执行选股逻辑。 3. 获取因子数据:获取当前时刻的因子值。 4. 因子处理:对因子进行标准化和中性化处理(这里以行业中性化为例,需要行业数据,但ptrade可能不直接提供,我们可以使用申万一级行业分类,但需要自己准备或从外部获取。这里为了简化,我们假设已经获取了行业数据,并演示中性化过程)。 5. 合成因子:将多个因子合成为一个综合因子(例如等权加权)。 6. 选股:根据综合因子排序,选择前N只股票。 7. 调整持仓:卖出不在新组合中的股票,买入新组合中的股票。 注意:由于ptrade的API限制,我们可能无法直接获取行业数据,因此在实际操作中,可能需要使用其他方式或者简化处理。这里我们主要展示框架。 代码示例: ```python import numpy as np import pandas as pd def initialize(context): # 设置回测参数 set_benchmark('000300.SH') # 设置基准为沪深300 set_option('use_real_price', True) # 使用真实价格 set_order_cost(OrderCost(open_tax=0, close_tax=0.001, open_commission=0.0003, close_commission=0.0003, min_commission=5), type='stock') # 设置多因子选股参数 g.stock_pool = get_index_stocks('000300.SH') # 初始股票池为沪深300成分股 g.factor_list = ['APM', 'momentum'] # 因子列表 g.neutralize_factors = True # 是否进行中性化处理 g.topN = 20 # 选前20只股票 # 设置调仓频率:每月第一个交易日 run_monthly(func=rebalance, date_rule=1) def rebalance(context): # 获取当前时间 now = context.current_dt # 获取股票池,这里可以动态更新,比如剔除ST、停牌、上市不足3个月的股票 stock_pool = get_stock_pool(now) # 获取因子数据 factor_data = get_factor_data(stock_pool, now) # 如果没有数据,则返回 if factor_data is None or len(factor_data) == 0: return # 因子处理(标准化、中性化) processed_factor = process_factor(factor_data, now) # 合成因子(这里采用等权加权,假设两个因子方向一致,且已经处理成越大越好) processed_factor['composite'] = processed_factor[g.factor_list].mean(axis=1) # 按综合因子排序 processed_factor = processed_factor.sort_values('composite', ascending=False) # 选择前topN的股票 selected_stocks = processed_factor.head(g.topN).index.tolist() # 调整持仓 adjust_portfolio(context, selected_stocks) def get_stock_pool(date): # 获取基础股票池(这里以沪深300为例) stock_pool = get_index_stocks('000300.SH', date) # 剔除ST股票 current_data = get_current_data() stock_pool = [s for s in stock_pool if not current_data[s].is_st] # 剔除停牌股票 stock_pool = [s for s in stock_pool if not current_data[s].paused] # 这里还可以剔除上市不足3个月的股票(需要获取上市日期,此处省略) return stock_pool def get_factor_data(stock_pool, date): # 初始化一个DataFrame来存储因子数据 factor_data = pd.DataFrame(index=stock_pool) # 获取APM因子(这里假设APM因子已经预先计算好并存储在某个地方,或者实时计算) # 由于APM因子的计算需要日内数据,且计算复杂,这里我们假设已经有一个函数可以获取 # 同样,动量因子我们使用过去20日的收益率 factor_data['APM'] = get_apm_factor(stock_pool, date) factor_data['momentum'] = get_momentum_factor(stock_pool, date, 20) # 删除有缺失值的行 factor_data = factor_data.dropna() return factor_data def get_apm_factor(stock_pool, date): # 这里简化处理:实际APM因子计算需要上午和下午的收益率数据,这里假设我们已经计算好并返回一个Series # 由于计算复杂,在实际中可能需要预先计算并存储,然后在策略中读取 apm_dict = {} for stock in stock_pool: # 这里仅作示例,实际需要根据引用[2]中的方法计算 # 我们假设有一个函数可以计算单只股票的APM因子 apm_dict[stock] = calculate_apm(stock, date) return pd.Series(apm_dict) def calculate_apm(stock, date): # 这里实现APM因子的计算,根据引用[2]: # 1. 获取股票在date日期前一段时间内的分钟数据(比如过去1个月) # 2. 将每天的交易时间分为上午(9:30-11:30)和下午(13:00-15:00) # 3. 计算上午收益率和下午收益率,然后计算它们的差值(或其他统计量)作为因子 # 由于计算复杂且需要分钟数据,这里我们返回一个随机数模拟(实际策略中需要替换) return np.random.randn() def get_momentum_factor(stock_pool, date, window): # 动量因子:过去window天的收益率 momentum_dict = {} # 获取历史收盘价 prices = get_history(window+1, '1d', 'close', stock_pool) for stock in stock_pool: # 计算收益率 close = prices[stock].values ret = (close[-1] - close[0]) / close[0] momentum_dict[stock] = ret return pd.Series(momentum_dict) def process_factor(factor_data, date): # 因子标准化:z-score标准化 for factor in g.factor_list: factor_data[factor] = (factor_data[factor] - factor_data[factor].mean()) / factor_data[factor].std() # 因子中性化(这里以行业中性化为例,需要行业数据) # 假设我们有一个函数get_industry返回每个股票的行业(申万一级行业代码) if g.neutralize_factors: # 获取行业信息 industry_data = get_industry(factor_data.index, date) # 将行业转换为虚拟变量 industry_dummies = pd.get_dummies(industry_data, prefix='ind') # 对每个因子进行行业中性化 for factor in g.factor_list: # 建立线性回归:因子 ~ 行业哑变量 X = industry_dummies y = factor_data[factor] # 使用线性回归得到残差作为中性化后的因子 from sklearn.linear_model import LinearRegression reg = LinearRegression().fit(X, y) factor_data[factor] = y - reg.predict(X) return factor_data def get_industry(stocks, date): # 获取股票的行业分类,这里假设我们有一个外部数据源或者字典 # 在实际中,可以使用ptrade的get_industry函数(如果提供的话)或者使用第三方数据 # 这里我们模拟一个行业分类 industry_dict = {} for stock in stocks: # 这里简单模拟,实际中需要根据股票获取行业 # 假设我们使用申万一级行业,这里用0到29的整数代表30个行业 industry_dict[stock] = np.random.randint(0,30) return pd.Series(industry_dict) def adjust_portfolio(context, selected_stocks): # 调整持仓至目标股票 # 先卖出当前持有但不在目标组合中的股票 for stock in context.portfolio.positions: if stock not in selected_stocks: order_target_value(stock, 0) # 买入目标组合中的股票,等权分配资金 total_value = context.portfolio.total_value weight = 1.0 / len(selected_stocks) if len(selected_stocks) > 0 else 0 for stock in selected_stocks: order_target_value(stock, total_value * weight) ``` 注意:以上代码为示例框架,实际运行需要根据ptrade的具体API进行调整,并且部分函数(如get_industry)需要根据实际情况实现。另外,APM因子的计算需要分钟级数据,这在ptrade中可能需要使用`get_price`或`get_bars`函数获取分钟线,然后进行计算,但计算量较大,可能影响回测速度。 此外,因子中性化部分使用了sklearn库,需要确保ptrade环境支持。如果不支持,可以自行编写线性回归函数,或者使用统计方法(如按行业分组后减去行业均值)。 由于多因子选股策略的复杂性,建议在实际应用中逐步测试每个因子的有效性,并注意过拟合问题。 参考文献: [^1]: ptrade从零开始学习量化交易第156期 [^2]: ptrade从零开始学习量化交易第177期 [^3]: ptrade从零开始学习量化交易第178期 [^4]: ptrade从零开始学习量化交易第179期 ### 相关问题 1. 如何在ptrade中获取分钟级数据并计算技术指标? 2. ptrade中如何实现因子中性化处理? 3. 如何评估多因子选股策略的绩效? 4. 在ptrade中如何动态更新股票池(如剔除ST股、停牌股等)? 5. 如何优化多因子选股策略的交易成本?</think>### 在 ptrade 中实现多因子选股策略的完整指南 多因子选股策略通过结合多个有效因子(如 APM 因子、动量因子等)来构建投资组合,可显著提高策略的稳定性和收益能力[^1]。以下是基于引用文献的 ptrade 实现框架: #### 核心实现步骤 ```python def initialize(context): # 基础设置 set_benchmark('000300.SH') # 沪深300基准 set_option('use_real_price', True) set_order_cost(OrderCost(open_tax=0, close_tax=0.001, open_commission=0.0003, close_commission=0.0003), type='stock') # 多因子参数 g.factors = ['APM', 'momentum'] # 因子列表 g.neutralize = True # 启用行业市值中性化 g.topN = 30 # 选股数量 # 定时每月调仓 run_monthly(rebalance, date_rule=1) def rebalance(context): # 获取合格股票池 stock_pool = get_qualified_stocks() # 获取因子数据 factor_df = get_factor_data(stock_pool, context.previous_date) # 因子处理(标准化+中性化) processed_df = process_factors(factor_df) # 合成综合因子 processed_df['composite'] = processed_df[g.factors].mean(axis=1) # 选股逻辑 selected_stocks = processed_df.sort_values('composite').head(g.topN).index.tolist() # 执行调仓 adjust_portfolio(context, selected_stocks) # 辅助函数:获取合格股票池 def get_qualified_stocks(): # 剔除ST、停牌、次新股 (引用[2]逻辑) all_stocks = get_index_stocks('000001.SH') + get_index_stocks('399001.SZ') current_data = get_current_data() return [s for s in all_stocks if not current_data[s].is_st and not current_data[s].paused and (datetime.now() - get_security_info(s).listing_date).days > 90] # 辅助函数:获取因子数据 def get_factor_data(stock_list, date): df = pd.DataFrame(index=stock_list) # APM因子计算 (引用[2]逻辑) df['APM'] = [calculate_apm(s, date) for s in stock_list] # 动量因子:20日收益率 (引用[3]逻辑) hist = get_history(20, '1d', 'close', stock_list) df['momentum'] = (hist.iloc[-1] - hist.iloc[0]) / hist.iloc[0] return df.dropna() # APM因子计算实现 def calculate_apm(stock, date): # 获取分钟级数据 (引用[2]核心逻辑) am_data = get_bars(stock, 30, '1m', fields=['close'], end_dt=date.replace(hour=11, minute=30)) pm_data = get_bars(stock, 30, '1m', fields=['close'], end_dt=date.replace(hour=15, minute=0)) am_ret = (am_data['close'][-1] - am_data['close'][0]) / am_data['close'][0] pm_ret = (pm_data['close'][-1] - pm_data['close'][0]) / pm_data['close'][0] return am_ret - pm_ret # 上午vs下午收益率差 # 因子处理 (引用[4]中性化方法) def process_factors(df): # Z-score标准化 for factor in g.factors: df[factor] = (df[factor] - df[factor].mean()) / df[factor].std() # 行业市值中性化 if g.neutralize: industries = get_industry(df.index) market_caps = get_valuation(df.index, 'market_cap') for factor in g.factors: # 构建线性回归: 因子 ~ 行业 + log(市值) model = LinearRegression() model.fit(pd.get_dummies(industries).join(np.log(market_caps)), df[factor]) df[factor] = df[factor] - model.predict(pd.get_dummies(industries).join(np.log(market_caps))) return df # 组合调整 def adjust_portfolio(context, target_stocks): current_holdings = set(context.portfolio.positions.keys()) target_set = set(target_stocks) # 卖出不在目标的持仓 for stock in current_holdings - target_set: order_target_value(stock, 0) # 买入目标股票 (等权配置) weight = context.portfolio.total_value / len(target_stocks) for stock in target_set: order_target_value(stock, weight) ``` #### 关键实现要点 1. **因子选择与计算** - **APM因子**:基于上午/下午收益率差异,反映知情交易者行为[^2] - **动量因子**:20日收益率捕捉趋势效应[^3] - 扩展建议:可添加价值因子(PE/PB)、波动率因子等 2. **因子处理技术** - **标准化**:使用Z-score消除量纲影响 $$ \text{z-score} = \frac{x - \mu}{\sigma} $$ - **中性化处理**:通过线性回归剔除行业和市值影响[^4] $$ \text{因子残差} = \text{原始因子} - (\beta_1 \times \text{行业} + \beta_2 \times \log(\text{市值})) $$ 3. **组合构建逻辑** - 每月初调仓,保持策略稳定性 - 等权重配置降低个股权重偏差 - 严格筛选股票池(剔除ST/次新/停牌股) 4. **绩效优化方向** - 因子加权:ICIR加权、因子收益率加权 - 动态因子选择:基于因子动量轮动 - 风险控制:最大回撤止损机制 > 实证显示:经过行业市值中性化的APM因子组合年化收益可达10.99%,夏普比率1.52,显著优于原始因子[^4]。 ### 注意事项 1. **数据获取**:分钟级数据需在`get_bars`中指定`include_now=True`获取当日数据 2. **行业分类**:使用`get_industry`获取申万一级行业分类 3. **回测验证**:建议先进行单因子有效性检验(分组收益分析)[^4] 4. **计算优化**:对于全市场选股,建议使用`parallel`参数并行计算 ### 相关问题 1. 如何在 ptrade 中实现因子中性化处理? 2. ptrade 中如何获取分钟级数据计算技术指标? 3. 如何评估多因子选股策略的绩效指标? 4. 在 ptrade 中如何实现动态因子权重调整? 5. 如何处理因子间的多重共线性问题?
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值