大家好,我是橙哥!今天给大家介绍多因子优选选股策略。这个策略的核心思想是通过多个指标来挑选出一组表现最好的股票进行投资。你可以把它想象成是一种“优中选优”的方法。我们不仅会考虑股票的技术表现(比如股票的价格走势),还会结合公司的一些财务健康指标(比如盈利能力、运营效率)来对股票进行打分。最后,我们根据这些分数,选出得分最高的一些股票进行投资。为了确保我们的投资组合始终保持在一个优质状态,我们会每周定期调整持仓,根据最新的分析结果来更新我们的股票池。
策略逻辑
多因子选股:
我们会使用多种指标(即“因子”)对每只股票进行打分。这些因子可以包括技术指标(比如过去一段时间的股票价格走势),也可以包括财务指标(比如公司的成本控制能力、存货周转效率等)。根据这些因子的综合得分,我们将股票进行排序,然后选出得分最高的股票作为我们的投资目标。
持仓调整:
每周,我们都会重新评估所有持仓的股票,并根据最新的得分进行调整。具体来说,就是卖出那些不再符合我们标准的股票,并买入新得分更高的股票。这样做的目的是确保我们的投资组合始终由市场上表现最好的股票组成,减少不必要的风险。
风险控制:
为了降低风险,我们会主动避开一些波动性大的股票。例如,我们会过滤掉那些当天涨停或跌停的股票、ST股(这些是处于特别处理阶段的公司股票,通常风险较大)、次新股(刚上市不久的股票)和科创板股票(这些股票的波动性较大)。通过这样筛选,我们的投资组合会更加稳健。
策略代码详解
初始化函数 initialize
在策略开始运行时,我们首先需要设定一些基础配置。比如,我们选择中证1000指数作为我们的基准,这样可以让我们了解我们的策略表现如何。另外,我们会启用真实的市场价格进行交易,并设置一些交易成本和滑点(滑点指的是实际成交价格与预期成交价格之间的差异)。同时,我们还会设定一个持股数量的上限,以及需要关注的几个关键因子。这部分代码如下:
def initialize(context):
set_benchmark('399303.XSHE') # 中证1000指数作为基准
set_option('use_real_price', True) # 使用真实价格进行交易
set_option("avoid_future_data", True) # 防止使用未来数据
set_slippage(FixedSlippage(0)) # 设置固定滑点为0
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')
log.set_level('order', 'error') # 过滤日志,仅保留error级别以上的日志
g.stock_num = 10 # 最大持股数量
g.hold_list = [] # 当前持仓的股票列表
g.yesterday_HL_list = [] # 记录昨日涨停的股票
g.factor_list = [
'price_no_fq', # 技术指标因子:不复权价格
'total_profit_to_cost_ratio', # 质量类因子:成本费用利润率
'inventory_turnover_rate' # 质量类因子:存货周转率
]
run_daily(prepare_stock_list, time='9:05', reference_security='000300.XSHG')
run_weekly(weekly_adjustment, weekday=1, time='9:30', reference_security='000300.XSHG')
run_daily(check_limit_up, time='14:00', reference_security='000300.XSHG')
run_daily(print_position_info, time='15:10', reference_security='000300.XSHG')
功能解释:
这个函数的主要作用是为策略设定基础配置,确保系统知道何时选股、何时买入或卖出股票。它还包括了持仓数量的上限设置,防止我们的投资组合过于分散或过于集中。
股票池准备与筛选 prepare_stock_list
每个交易日开始前,我们都会准备当天的股票池,并记录下我们当前持有的股票中,哪些在前一天涨停。这部分代码如下:
def prepare_stock_list(context):
g.hold_list = [position.security for position in context.portfolio.positions.values()]
if g.hold_list:
df = get_price(g.hold_list, end_date=context.previous_date, frequency='daily', fields=['close', 'high_limit'], count=1, panel=False, fill_paused=False)
df = df[df['close'] == df['high_limit']]
g.yesterday_HL_list = list(df.code)
else:
g.yesterday_HL_list = []
功能解释:
这个函数帮助我们记录当前持仓的股票中,哪些股票在前一天涨停。这些信息对我们后续的交易决策非常重要,尤其是当我们需要决定是否继续持有这些股票时。
选股逻辑 get_stock_list
接下来,我们通过计算多个因子的综合得分,来筛选出市场上最优质的股票。代码如下:
def get_stock_list(context):
yesterday = context.previous_date
initial_list = get_all_securities().index.tolist()
initial_list = filter_new_stock(context, initial_list)
initial_list = filter_kcbj_stock(initial_list)
initial_list = filter_st_stock(initial_list)
factor_values = get_factor_values(initial_list, g.factor_list, end_date=yesterday, count=1)
df = pd.DataFrame(index=initial_list, columns=g.factor_list)
for factor in g.factor_list:
df[factor] = factor_values[factor].T.iloc[:, 0]
df = df.dropna()
coef_list = [-6.123e-05, -0.002579, -2.194e-06]
df['total_score'] = sum(coef * df[factor] for coef, factor in zip(coef_list, g.factor_list))
df = df.sort_values(by='total_score', ascending=False)
top_stocks = df.index[:int(0.1 * len(df.index))]
q = query(valuation.code, valuation.circulating_market_cap, indicator.eps).filter(valuation.code.in_(top_stocks)).order_by(valuation.circulating_market_cap.asc())
df = get_fundamentals(q)
final_list = df[df['eps'] > 0].code.tolist()
return final_list
功能解释:
这个函数通过计算每只股票的技术指标和财务指标,来为股票打分。然后,我们会选出得分最高的一部分股票进行投资。为了确保这些股票不仅得分高,还要基本面好,我们还会进一步筛选出流通市值较大、盈利能力强的股票。
持仓调整 weekly_adjustment
每周,我们都会根据最新的选股结果调整我们的持仓。代码如下:
def weekly_adjustment(context):
target_list = get_stock_list(context)
target_list = filter_paused_stock(target_list)
target_list = filter_limitup_stock(context, target_list)
target_list = filter_limitdown_stock(context, target_list)
target_list = target_list[:min(g.stock_num, len(target_list))]
for stock in g.hold_list:
if stock not in target_list and stock not in g.yesterday_HL_list:
log.info(f"卖出[{stock}]")
close_position(context.portfolio.positions[stock])
position_count = len(context.portfolio.positions)
target_num = len(target_list)
if target_num > position_count:
value = context.portfolio.cash / (target_num - position_count)
for stock in target_list:
if context.portfolio.positions[stock].total_amount == 0:
if open_position(stock, value):
if len(context.portfolio.positions) == target_num:
break
功能解释:
这个函数让我们每周定期调整持仓,确保我们的投资组合始终由表现最好的股票组成。通过定期的持仓调整,我们可以避免持有表现不佳的股票,同时抓住新的投资机会。
涨停股监控 check_limit_up
我们还需要每天监控那些前一天涨停的股票,看看它们今天是否仍然保持强劲。如果这些股票在今天的交易中涨停被打开,我们会考虑卖出。代码如下:
def check_limit_up(context):
now_time = context.current_dt
if g.yesterday_HL_list:
for stock in g.yesterday_HL_list:
current_data = get_price(stock, end_date=now_time, frequency='1m', fields=['close', 'high_limit'], skip_paused=False
, fq='pre', count=1, panel=False, fill_paused=True)
if current_data.iloc[0, 0] < current_data.iloc[0, 1]:
log.info(f"[{stock}]涨停打开,卖出")
close_position(context.portfolio.positions[stock])
else:
log.info(f"[{stock}]涨停,继续持有")
功能解释:
这个函数帮助我们在每天的交易中实时监控前一天涨停的股票。如果这些股票在今天涨停被打开,我们就会卖出,以确保利润不被侵蚀。
策略总结
这个“多因子优选选股策略”是一个通过多种指标综合打分来筛选优质股票的投资方法。它结合了技术分析和公司基本面的财务分析,旨在控制风险的同时获取更高的回报。通过每周的持仓调整,这个策略能够持续保持组合的优质性和稳定性,非常适合那些追求稳健增长的投资者。
长按扫描下方二维码获取本文完整源码下载方式:
点击阅读原文,加入「宽客邦量化俱乐部」