社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

ETF策略的四大模板:资产配置、多因子轮动,择时以及策略组合,附python代码

七年实现财富自由 • 10 月前 • 397 次点击  
原创内容第1050篇,专注AGI+,AI量化投资、个人成长与财富自由
立足长期去规划一件事,去做一件事,打磨一个产品,“小而美”,“小而精”。
有时候,慢就是快。
回归投资的“第一性原理”。
我把ETF策略总结为四大模板:资产配置、多因子轮动,择时以及策略组合
  1. 涵盖所有维度

  • 横截面(轮动):在多个ETF中选择

  • 时间序列(择时):对单个ETF择时

  • 权重分配(配置):确定持仓比例

  • 组合构建(组合):策略层面组合


  • 可组合性任何复杂策略都可以拆解为这四种基本操作的组合

  • 从这个意义上讲,ETF策略的玩法比股票还多。

    股票基本没有组合的概念,单支择时意义有限,更不需要多个策略组合,股票的主流策略是“多因子轮动”。

    从策略模板设计上股票更为简单——不需要区分买入、卖出规则,直接一个筛选规则就好了。

    当然工程上,股票数量大,还需要财务报表这样的多因子,因此,在数据计算、性能以及因子存储上,更复杂,要求更高,在多因子上的玩法也更多。

    另外还有一个很大的差别,也就是股票一般是选股机制,比如通过截面因子,基本面因子来选股,而etf多是主观确定etf池——这一块可以交给大模型智能体去优化。

    如下代码就包含了这四种类型,以及各种止盈、止损的方式,我们可以各种因子,组合出各种策略:

    from dataclasses import dataclass, fieldfrom datetime import datetimefrom typing import ListDictOptionalUnionfrom enum import Enum

    class StrategyType(Enum):    ASSET_ALLOCATION = "asset_allocation"    ROTATION = "rotation"    TIMING = "timing"    PORTFOLIO = "portfolio"

    class WeightMethod(Enum):    EQUALLY = "WeightEqually"    FIXED = "WeightFixed"    RISK_PARITY = "WeightRiskParity"    VOLATILITY = "WeightVolatility"

    class PeriodType(Enum):    DAILY = "RunDaily"    WEEKLY = "RunWeekly"    MONTHLY = "RunMonthly"    QUARTERLY = "RunQuarterly"    YEARLY = "RunYearly"    Once = 'RunOnce'    CUSTOM_DAYS = "custom_days"

    class StopLossType(Enum):    FIXED = "fixed"  # 固定止损    TRAILING = "trailing"  # 移动止损    TIME_BASED = "time_based"  # 时间止损    TECHNICAL = "technical"  # 技术指标止损    VOLATILITY = "volatility"  # 波动率止损    COMBINED = "combined"  # 组合止损

    @dataclass class FixedStopLossConfig:    """固定止损配置"""    loss_threshold: float  # 亏损阈值 X%,例如 0.1 表示亏损10%    sell_ratio: float  # 卖出仓位比例 Y%,例如 0.5 表示卖出50%仓位    enabled: bool = True
        def __post_init__(self):        if not 0 self.loss_threshold <= 1:            raise ValueError("loss_threshold 必须在 (0, 1] 范围内")        if not 0 self.sell_ratio <= 1:            raise ValueError("sell_ratio 必须在 (0, 1] 范围内")

    @dataclassclass TrailingStopLossConfig:    """移动止损配置"""    profit_threshold: float  # 盈利阈值 X%,例如 0.2 表示盈利20%    pullback_threshold: float  # 回落阈值 Y%,例如 0.05 表示回落5%    sell_ratio: float  # 卖出仓位比例 Z%,例如 0.3 表示卖出30%仓位    enabled: bool = True
        def __post_init__(self):        if not 0 self.profit_threshold <= 1:            raise ValueError("profit_threshold 必须在 (0, 1] 范围内")        if not 0 self.pullback_threshold <= 1:            raise ValueError("pullback_threshold 必须在 (0, 1] 范围内")        if not 0 self.sell_ratio <= 1:            raise ValueError("sell_ratio 必须在 (0, 1] 范围内")

    @dataclassclass TimeBasedStopLossConfig:    """时间止损配置"""    max_hold_days: int  # 最大持有天数    sell_ratio: float = 1.0  # 卖出比例    enabled: bool = True
        def __post_init__(self):        if self.max_hold_days <= 0:            raise ValueError("max_hold_days 必须大于0")        if not 0 self.sell_ratio <= 1:            raise ValueError("sell_ratio 必须在 (0, 1] 范围内")

    @dataclassclass TechnicalStopLossConfig:    """技术指标止损配置"""    indicator: str  # 技术指标,如 'ma', 'boll', 'macd'    condition: str  # 条件,如 'close < ma20', 'close < boll_lower'    sell_ratio: float = 1.0  # 卖出比例    enabled: bool = True
        def __post_init__(self):        if not 0 self.sell_ratio <= 1:            raise ValueError("sell_ratio 必须在 (0, 1] 范围内")

    @dataclassclass VolatilityStopLossConfig:    """波动率止损配置"""    atr_multiplier: float = 2.0  # ATR乘数    lookback_period: int = 14  # 回看周期    sell_ratio: float = 1.0  # 卖出比例    enabled: bool = True
        def __post_init__(self):        if self.atr_multiplier <= 0:            raise ValueError("atr_multiplier 必须大于0")        if self.lookback_period <= 0:             raise ValueError("lookback_period 必须大于0")        if not 0 self.sell_ratio <= 1:            raise ValueError("sell_ratio 必须在 (0, 1] 范围内")

    @dataclassclass StopLossConfig:    """止损配置(主要用于择时策略)"""    stop_loss_type: StopLossType = StopLossType.COMBINED
        # 各种止损方式配置    fixed_stop_losses: List[FixedStopLossConfig] = field(default_factory=list)    trailing_stop_losses: List[TrailingStopLossConfig] = field(default_factory=list)    time_based_stop_losses: List[TimeBasedStopLossConfig] = field(default_factory=list)    technical_stop_losses: List[TechnicalStopLossConfig] = field(default_factory=list)    volatility_stop_losses: List[VolatilityStopLossConfig] = field(default_factory=list)
        # 止损执行优先级(数字越小优先级越高)    execution_priority: List[StopLossType] = field(default_factory=lambda: [        StopLossType.FIXED,        StopLossType.TRAILING,        StopLossType.TECHNICAL,        StopLossType.VOLATILITY,        StopLossType.TIME_BASED    ])

    @dataclassclass BaseTask:    """基础策略配置"""    strategy_type: StrategyType    symbols: List[str] = field(default_factory=list)
        # 回测参数    # start_date: str = '20100101'    # end_date: str = field(default_factory=lambda: datetime.now().strftime('%Y%m%d'))    # benchmark: str = '510300.SH'    # initial_capital: float = 1000000.0
        # 执行周期    period: PeriodType = PeriodType.DAILY    period_days: Optional[int] = None
        # 风险控制    max_position_ratio: float = 1.0  # 最大持仓比例

    @dataclassclass AssetAllocationTask(BaseTask):    """资产配置策略"""    strategy_type: StrategyType = StrategyType.ASSET_ALLOCATION
        # 权重配置    weight_method: WeightMethod = WeightMethod.EQUALLY    weight_fixed: Dict[strfloat] = field(default_factory=dict)    risk_parity_target: Optional[float] = None  # 风险平价目标波动率
        # 再平衡配置    rebalance_threshold: float = 0.05  # 再平衡阈值    dynamic_rebalance: bool = True  # 是否动态再平衡

    @dataclassclass RotationTask(BaseTask):    """轮动策略"""    strategy_type: StrategyType = StrategyType.ROTATION
        # 筛选规则    select_buy_rules: List[str] = field(default_factory=list)    select_sell_rules: List[str] = field(default_factory=list)
        # 数量控制    min_hold_count: int = 1    max_hold_count: int = 10    buy_at_least_count: int = 0    sell_at_least_count: int = 1
        # 排序配置    order_by_signal: str = ''    order_by_topK: int = 5    order_by_dropN: int = 0    order_by_desc: bool = True
        # 轮动参数    rotation_threshold: float = 0.02  # 轮动阈值    hold_period: Optional[int] = None  # 最小持有期

    @dataclassclass TimingTask(BaseTask):    """择时策略"""    strategy_type: StrategyType = StrategyType.TIMING
        # 信号规则    buy_rules: List[str] = field(default_factory=list)    sell_rules: List[str] = field(default_factory=list)
        # 仓位管理    position_size: float = 1.0  # 每次开仓比例    pyramiding: int = 1  # 加仓次数
        # 止盈止损配置(择时策略特有)    stop_loss_config: StopLossConfig = field(default_factory=StopLossConfig)
        # 技术指标参数    use_technical: bool = False    technical_params: Dict[strfloat] = field(default_factory=dict)

    @dataclassclass PortfolioTask(BaseTask):    """策略组合"""    strategy_type: StrategyType = StrategyType.PORTFOLIO
        # 子策略配置    sub_strategies: List[Union[AssetAllocationTask, RotationTask, TimingTask]] = field(default_factory=list)
        # 资金分配    weight_method: WeightMethod = WeightMethod.EQUALLY    strategy_weights: Dict[strfloat] = field(default_factory=dict)  # 策略名称:权重
        # 组合风控    correlation_threshold: float = 0.8  # 策略相关性阈值    max_drawdown_control: bool = True

    # 使用示例if __name__ == "__main__":    # 资产配置策略示例(不需要止盈止损)    asset_task = AssetAllocationTask(        symbols=['510300.SH''510500.SH''159915.SZ'],        weight_method=WeightMethod.FIXED,        weight_fixed={'510300.SH'0.5'510500.SH'0.3'159915.SZ'0.2},        period=PeriodType.MONTHLY,        rebalance_threshold=0.1    )
        # 轮动策略示例(通常也不需要复杂的止盈止损)    rotation_task = RotationTask(        symbols=['512100.SH''512000.SH''512700.SH''515000.SH'],        select_buy_rules=['pe_ratio < 20''pb_ratio < 2'],        order_by_signal='momentum_score',        order_by_topK=2,        period=PeriodType.WEEKLY    )
        # 择时策略示例(需要丰富的止盈止损配置)    timing_task = TimingTask(        symbols=['510300.SH'],        buy_rules=['close > ma20''rsi < 30'],        sell_rules=['close < ma20''rsi > 70'],        position_size=0.8,        stop_loss_config=StopLossConfig(            fixed_stop_losses=[                FixedStopLossConfig(loss_threshold=0.05, sell_ratio=0.3),  # 亏损5%卖出30%                FixedStopLossConfig(loss_threshold=0.08, sell_ratio=0.5),  # 亏损8%卖出50%                FixedStopLossConfig(loss_threshold=0.12, sell_ratio=1.0)  # 亏损12%全部卖出            ],            trailing_stop_losses=[                TrailingStopLossConfig(profit_threshold=0.15, pullback_threshold=0.03, sell_ratio=0.2),                # 盈利15%后回落3%卖出20%                TrailingStopLossConfig(profit_threshold=0.25, pullback_threshold=0.05, sell_ratio=0.5),                # 盈利25%后回落5%卖出50%                TrailingStopLossConfig(profit_threshold=0.4, pullback_threshold=0.08, sell_ratio=1.0)  # 盈利40%后回落8%全部卖出            ],            time_based_stop_losses=[                TimeBasedStopLossConfig(max_hold_days=30, sell_ratio=0.5),  # 持有30天卖出50%                TimeBasedStopLossConfig(max_hold_days=60, sell_ratio=1.0)  # 持有60天全部卖出             ],            technical_stop_losses=[                TechnicalStopLossConfig(                    indicator='ma',                    condition='close < ma20',                    sell_ratio=0.5                ),                TechnicalStopLossConfig(                    indicator='boll',                    condition='close < boll_lower',                    sell_ratio=0.3                )            ],            volatility_stop_losses=[                VolatilityStopLossConfig(                    atr_multiplier=2.0,                    lookback_period=14,                    sell_ratio=0.5                )            ]        )    )
        # 策略组合示例    portfolio_task = PortfolioTask(        sub_strategies=[asset_task, rotation_task, timing_task],        weight_method=WeightMethod.FIXED,        strategy_weights={'asset_allocation'0.4'rotation'0.4'timing'0.2}    )
    每天“不管”一点点,每天就变强一天天。
    代码和数据下载:AI量化实验室——2025量化投资的星辰大海

    AI量化实验室 星球,已经运行三年多,2000+会员。

    aitrader代码,因子表达式引擎、遗传算法(Deap)因子挖掘引等,支持vnpy,qlib,backtrader和bt引擎,内置多个年化30%+的策略,每周五迭代一次,代码和数据在星球全部开源。


    点击 “查看原文”,直接访问策略集合

    扩展  •  历史文章   


    星球排名第一的策略更新了,可以订阅了: 年化560%,回撤9%,夏普6.01 | 自改进大语言模型框架,用于量化交易信号挖掘。

    Quant4.0,基于AgentScope开发 | 年化316%,回撤14%的超级轮动策略,附python代码

    年化30.24%,最大回撤19%,综合动量多因子评分策略再升级(python代码+数据)

    年化429%,夏普5.51 | 全A股市场回测引擎构建

    Python社区是高质量的Python/Django开发社区
    本文地址:http://www.python88.com/topic/189001