全A股小市值和动量因子策略:最大化年化收益
由polll创建,最终由polll 被浏览 130 用户
策略介绍
量化投资领域中,因子模型是非常重要的一类策略。因子投资策略通过提取市场中的某些特征(如价值、动量、规模等),并以此来构建投资组合。本文介绍的策略主要采用了小市值因子和动量因子,目的是在全A股市场中最大化年化收益率。
小市值因子(Size Factor)指的是选取市值较小的股票进行投资。根据“规模效应”理论,市值较小的股票往往能够获得较高的收益率。动量因子(Momentum Factor)则是选取价格上升趋势明显的股票进行投资。动量策略的理论基础是“惯性效应”,即股票价格在一段时间内的走势会继续保持。
这两个因子的结合可以捕捉到市场中的不同特征,从而提高策略的收益。需要注意的是,该策略不做风险控制,适合风险承受能力较高的投资者。
策略流程
- 股票池:全A股市场,不需要额外的股票池过滤。
- 排序条件:基于小市值因子和动量因子,按综合得分进行排序。
- 筛选条件:无特别指定的筛选条件。
- 持仓配置:持有数量和仓位分配。
- 交易逻辑:每月调仓一次。
- 风险管理:不做风险控制。
策略实现
模块说明
- input_features_dai:输入特征模块,用于构建因子表达式。该模块输入小市值因子和动量因子的表达式,并计算综合得分。
- score_to_position:仓位分配模块,根据综合得分对股票进行排序,并设置持仓数量和分配。
- bigtrader:高性能回测模块,实现回测逻辑,设置调仓周期、初始资金等参数。
因子表达式
因子表达式的构建如下:
-
小市值因子:使用流通市值因子
float_market_cap
-
动量因子:使用5日动量因子
momentum_5
-
综合得分表达式:
c_rank(float_market_cap) AS size_score, c_rank(momentum_5) AS momentum_score, size_score + momentum_score AS score
策略实现
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
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="-315,-727", comment="""因子特征""", comment_collapsed=False)
m2 = M.input_features_dai.v29( # type: ignore
mode="表达式",
expr="""
c_rank(float_market_cap) AS size_score
c_rank(momentum_5) AS momentum_score
size_score + momentum_score AS score
""",
expr_filters="",
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=50,
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="月度交易日",
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>
\