基于中证红利的股息率与ROE选股策略
由jliang创建,最终由jliang 被浏览 130 用户
策略介绍
中证红利指数(CSI Dividend Index)是由中证指数公司编制的,旨在反映中国A股市场中高股息率股票的整体表现。该指数选取了股息率较高的股票构成样本,具有较低的波动性和较高的分红收益率,是稳健投资者喜爱的标的。
本策略主要通过筛选中证红利指数中的股票,重点考虑股息率(Dividend Yield)和净资产收益率(Return on Equity,ROE)两个因子。股息率是衡量股票分红收益的一项指标,而ROE则反映了企业运用资本的效率。综合考虑这两个因子,可以筛选出既能提供高分红,又具有较好运营能力的股票,进而实现稳健的收益。
回撤控制和夏普率的提升是本策略的两个关键目标。回撤控制旨在减少投资组合在市场波动中的损失,而夏普率则衡量了单位风险下的收益水平。因此,在策略设计中,除了关注选股因子,还需加入适当的风险管理措施,如止盈和止损策略,以实现稳定的收益。
策略流程
- 股票池:从中证红利指数中选择股票。
- 排序条件:根据股息率和ROE的综合评分进行排序。
- 筛选条件:默认不做额外的筛选,以保证样本的多样性和代表性。
- 仓位设置:等权重持有评分最高的前N只股票,持仓数量可根据实际需求调整。
- 交易逻辑:每日调仓,根据最新的股息率和ROE数据进行排序和选股。
- 风险管理:通过设置止盈和止损点,控制回撤,提高夏普率。
策略实现
模块说明
cn_stock_basic_selector:A股-基础选股,用于筛选中证红利指数中的股票。 参数:
indexes=["中证红利"]
input_features_dai:输入特征(DAI),用于构建股息率和ROE因子。 参数:
expr="""
dividend_yield_ratio AS div_yield
roe_avg_ttm AS roe
(div_yield + roe) AS score
"""
score_to_position:仓位分配,根据股息率和ROE的综合评分进行排序,并等权重分配仓位。 参数:
score_field="score DESC"
hold_count=10(持仓数量可以根据需求调整)
position_expr="1 AS position"
extract_data_dai:数据抽取,用于抽取传入的sql数据。 参数:
start_date="2016-06-01"
end_date="2024-04-29"
bigtrader:BigTrader(高性能回测),实现回测逻辑。 参数:
capital_base=1000000
frequency="daily"
rebalance_period_type="daily"
因子表达式
因子表达式主要包括股息率和ROE:
dividend_yield_ratio AS div_yield
roe_avg_ttm AS roe
策略代码
from bigmodule import M
# <aistudiograph>
# @param(id="m5", name="initialize")
def m5_initialize_bigquant_run(context): # type: ignore
from bigtrader.finance.commission import PerOrder
# 系统已经设置了默认的交易手续费和滑点,要修改手续费可使用如下函数
context.set_commission(PerOrder(buy_cost=0.0003, sell_cost=0.0013, min_cost=5))
# @param(id="m5", name="handle_data")
def m5_handle_data_bigquant_run(context, data): # type: ignore
import pandas as pd
# 下一个交易日不是调仓日,则不生成信号
if not context.rebalance_period.is_signal_date(data.current_dt.date()):
return
# 从传入的数据 context.data 中读取今天的信号数据
today_df = context.data[context.data["date"] == data.current_dt.strftime("%Y-%m-%d")]
target_instruments = set(today_df["instrument"])
# 获取当前已持有股票
holding_instruments = set(context.get_account_positions().keys())
# 卖出不在目标持有列表中的股票
for instrument in holding_instruments - target_instruments:
context.order_target_percent(instrument, 0)
# 买入目标持有列表中的股票
for i, x in today_df.iterrows():
position = 0.0 if pd.isnull(x.position) else float(x.position)
context.order_target_percent(x.instrument, position)
# @module(position="-437,-854", comment="""使用基本信息对股票池过滤""", comment_collapsed=False)
m1 = M.cn_stock_basic_selector.v6( # type: ignore
exchanges=["上交所", "深交所", "北交所"],
list_sectors=["主板", "创业板", "科创板"],
indexes=["中证红利"],
st_statuses=["正常", "ST", "*ST"],
margin_tradings=["两融标的", "非两融标的"],
sw2021_industries=["农林牧渔", "采掘", "基础化工", "钢铁", "有色金属", "建筑建材", "机械设备", "电子", "汽车", "交运设备", "信息设备", "家用电器", "食品饮料", "纺织服饰", "轻工制造", "医药生物", "公用事业", "交通运输", "房地产", "金融服务", "商贸零售", "社会服务", "信息服务", "银行", "非银金融", "综合", "建筑材料", "建筑装饰", "电力设备", "国防军工", "计算机", "传媒", "通信", "煤炭", "石油石化", "环保", "美容护理"],
drop_suspended=True,
m_name="m1"
)
# @module(position="-315,-727", comment="""因子特征""", comment_collapsed=False)
m2 = M.input_features_dai.v29( # type: ignore
# 如果没有上游模块,则不需要 input_1 参数,不能设置为 None
input_1=m1.data,
mode="表达式",
expr="""
dividend_yield_ratio AS div_yield
roe_avg_ttm AS roe
(div_yield + roe) AS score
""",
expr_tables="cn_stock_prefactors",
extra_fields="date, instrument",
order_by="date, instrument",
expr_drop_na=True,
extract_data=False,
m_name="m2"
)
# @module(position="-207,-592", comment="""持股数量、打分到仓位""", comment_collapsed=False)
m3 = M.score_to_position.v3( # type: ignore
input_1=m2.data,
score_field="score DESC",
hold_count=10,
position_expr="1 AS position",
total_position=1,
extract_data=False,
m_name="m3"
)
# @module(position="-98,-463", comment="""抽取预测数据""", comment_collapsed=False)
m4 = M.extract_data_dai.v17( # type: ignore
sql=m3.data,
start_date="2016-06-01",
start_date_bound_to_trading_date=True,
end_date="2024-04-29",
end_date_bound_to_trading_date=True,
before_start_days=90,
debug=False,
m_name="m4"
)
# @module(position="43,-350", comment="""交易,日线,设置初始化函数和K线处理函数,以及初始资金、基准等""", comment_collapsed=False)
m5 = M.bigtrader.v20( # type: ignore
data=m4.data,
start_date="",
end_date="",
initialize=m5_initialize_bigquant_run,
handle_data=m5_handle_data_bigquant_run,
capital_base=1000000,
frequency="daily",
product_type="股票",
rebalance_period_type="daily",
rebalance_period_days="1",
rebalance_period_roll_forward=True,
backtest_engine_mode="标准模式",
before_start_days=0,
volume_limit=1,
order_price_field_buy="open",
order_price_field_sell="open",
benchmark="沪深300指数",
plot_charts=True,
debug=False,
backtest_only=False,
m_name="m5"
)
# </aistudiograph>
\