问题描述
解决方案
在聚宽(JoinQuant)平台上使用 Alpha191 因子库进行选股,主要依赖于 jqlib.alpha191 库。该库内置了国泰君安研报中的191个短周期量价因子。
使用 Alpha191 进行选股的核心流程通常如下:
- 确定股票池:如沪深300、中证500等。
- 获取因子值:调用
alpha_XXX函数获取指定日期的因子数据。 - 数据清洗:剔除停牌、ST股、涨跌停股票,处理因子缺失值。
- 排序选股:根据因子值大小进行排序(正向或反向),选取头部股票。
- 交易执行:调仓买入目标股票,卖出不在目标列表中的持仓。
下面是一个完整的单因子选股策略示例。该策略以 Alpha_001 为例,在沪深300成分股中选取因子值最大的前10只股票进行每日调仓。
策略代码示例
# -*- coding: utf-8 -*-
from jqdata import *
# 导入 Alpha191 库
from jqlib.alpha191 import *
def initialize(context):
"""
初始化函数,设定基准、手续费、滑点等
"""
# 设定沪深300作为基准
set_benchmark('000300.XSHG')
# 开启动态复权模式(真实价格)
set_option('use_real_price', True)
# 过滤掉order系列API产生的比error级别低的log
log.set_level('order', 'error')
# 设定股票池:沪深300
g.index = '000300.XSHG'
# 设定持仓数量
g.stock_num = 10
# 设定交易费率(股票:买入万三,卖出万三加千一印花税)
set_order_cost(OrderCost(open_tax=0, close_tax=0.001, open_commission=0.0003, close_commission=0.0003, close_today_commission=0, min_commission=5), type='stock')
# 每日开盘时运行选股和交易逻辑
run_daily(trade_func, time='09:30')
def trade_func(context):
"""
交易主逻辑
"""
# 1. 获取股票池(沪深300)
stocks = get_index_stocks(g.index)
# 2. 过滤掉停牌、ST、退市的股票
stocks = filter_stocks(stocks)
if not stocks:
return
# 3. 获取 Alpha191 中的 Alpha_001 因子值
# 注意:因子计算通常基于收盘后数据,所以使用 context.previous_date
# alpha_001 公式: (-1 * CORR(RANK(DELTA(LOG(VOLUME),1)),RANK(((CLOSE-OPEN)/OPEN)),6)
factor_data = alpha_001(stocks, end_date=context.previous_date)
# 4. 处理因子数据
# 去除 NaN 值
factor_data = factor_data.dropna()
# 5. 选股逻辑
# 这里假设因子值越大越好(具体方向需根据每个因子的定义来判断)
# 对因子值进行降序排列,取前 g.stock_num 只股票
target_list = factor_data.sort_values(ascending=False).head(g.stock_num).index.tolist()
# 6. 执行交易
rebalance(context, target_list)
def filter_stocks(stock_list):
"""
过滤停牌、ST、退市股票
"""
curr_data = get_current_data()
return [stock for stock in stock_list if
not curr_data[stock].paused and
not curr_data[stock].is_st and
'ST' not in curr_data[stock].name and
'*' not in curr_data[stock].name and
not curr_data[stock].day_open == curr_data[stock].high_limit and # 过滤涨停
not curr_data[stock].day_open == curr_data[stock].low_limit # 过滤跌停
]
def rebalance(context, target_list):
"""
调仓函数
"""
# 获取当前持仓
current_holdings = list(context.portfolio.positions.keys())
# 卖出不在目标列表中的股票
for stock in current_holdings:
if stock not in target_list:
order_target_value(stock, 0)
# 买入目标列表中的股票
if len(target_list) > 0:
# 等权重分配资金
value_per_stock = context.portfolio.total_value / len(target_list)
for stock in target_list:
order_target_value(stock, value_per_stock)
关键点说明
-
库的导入:
必须使用from jqlib.alpha191 import *才能直接调用alpha_001到alpha_191这些函数。 -
日期参数:
调用因子函数时(如alpha_001(stocks, end_date=...)),end_date通常传入context.previous_date。因为 Alpha191 多为日线级别的量价因子,需要在前一交易日收盘后计算,用于指导当天的交易。 -
因子方向:
Alpha191 中的因子有些是动量型的(值越大越好),有些是反转型的(值越小越好),还有些可能需要取绝对值。在使用具体因子前,建议查阅 Alpha191 的因子公式说明或进行简单的 IC 测试来确定排序方向(ascending=True还是False)。 -
多因子组合:
上述代码仅演示了单因子选股。如果需要使用多个因子,可以获取多个因子的 Series,将其合并为 DataFrame,进行标准化(Z-Score)处理后,加权求和得到综合得分,再进行排序选股。
Q&A
Q1: 如何查看 Alpha191 中某个具体因子的公式含义?
A1: 在聚宽的研究环境中,导入库后可以使用 ? 查看文档字符串。例如输入 alpha_001? 并运行,系统会显示该因子的计算公式和输入输出说明。
Q2: Alpha191 因子可以直接用于实盘吗?
A2: Alpha191 是短周期量价因子,换手率通常较高。直接使用原始因子可能面临较高的交易成本和滑点影响。建议在实盘前进行充分的回测,并考虑加入换手率限制、平滑处理或结合基本面因子使用。
Q3: 为什么有些因子计算结果全是 NaN?
A3: 这通常是因为计算该因子所需的历史数据长度不足。例如某些因子需要过去20天的移动平均,如果股票刚上市不足20天,或者传入的股票池中有停牌导致数据缺失,计算结果就会是 NaN。代码中应包含 dropna() 处理。