包含4份核心文档: - 轮动策略系统架构分析报告 - 量化策略通用框架抽象设计 - Freqtrade架构调研与对比分析 - ETF轮动策略通用化重构方案 调研结论:三种策略可抽象通用框架 设计决策:因子注册器风格 + 5个核心回调钩子 + TopN/Trend/Reversal信号生成器
15 KiB
15 KiB
ETF轮动策略系统架构分析与通用化设计报告
一、现有系统架构分析
1.1 整体架构概览
etf/
├── config/ # 配置中心
│ └── strategies/
│ └── rotation.yaml # 策略参数配置
├── core/ # 核心基础设施
│ ├── common/ # 公共工具(utils、db、notify)
│ ├── datasource/ # 数据源层(混合数据源、统一fetcher)
│ └── factors/ # 因子计算层(动量、技术指标)
├── strategies/ # 策略层
│ ├── base.py # 策略抽象基类
│ └── rotation/ # 轮动策略实现
│ ├── engine.py # 策略引擎(核心逻辑)
│ ├── portfolio.py # 持仓跟踪与交易记录
│ └── report.py # 绩效报告生成
├── scripts/ # 运行入口
│ └── run_rotation.py # 回测脚本
├── visualization/ # 可视化层
│ └── report_generator/ # HTML报告生成器
└── tests/ # 测试与实验
1.2 核心模块职责
| 模块 | 职责 | 关键文件 |
|---|---|---|
| 数据源层 | 多源数据获取、SSH隧道、缓存管理 | hybrid_source.py, universal_fetcher.py |
| 因子层 | 动量得分计算、崩盘过滤、ATR动态周期 | momentum.py |
| 策略引擎 | 信号生成、选股逻辑、调仓控制 | engine.py |
| 持仓跟踪 | 交易记录、持仓统计、汇总 | portfolio.py |
| 报告层 | KPI计算、图表绘制、HTML生成 | report.py, generate_report.py |
1.3 策略核心流程
graph TB
A[配置加载] --> B[数据获取]
B --> C[因子计算]
C --> D[信号生成]
D --> E[回测执行]
E --> F[持仓跟踪]
F --> G[报告生成]
B --> B1[Tushare A股]
B --> B2[YFinance 港美股]
B --> B3[SSH隧道代理]
C --> C1[加权动量得分]
C --> C2[崩盘过滤]
C --> C3[溢价控制]
D --> D1[类内竞争Top1]
D --> D2[跨类排序Top3]
D --> D3[T+1执行]
二、现有实现特点分析
2.1 数据层设计
优点:
- 混合数据源架构:Tushare(A股) + YFinance(港美股)
- SSH隧道统一治理:解决网络受限环境问题
- 双轨数据架构:指数价格(信号源)+ ETF价格(收益计算)
- 智能路由:根据代码格式自动选择数据源
问题:
- ETF列名与指数代码不匹配导致收益计算使用错误数据源
- 缓存策略过于简单,缺乏版本控制
2.2 因子层设计
优点:
- 三种因子类型:momentum、slope_r2、weighted_momentum
- 崩盘过滤机制:防止追接下跌飞刀
- ATR动态周期:自适应市场波动
- 加权线性回归:近期权重更高,对趋势变化敏感
问题:
- 因子类型固定,扩展需修改源码
- 缺乏因子组合/加权机制
2.3 策略层设计
优点:
- 分散化选股:每大类Top1→全局Top3,强制跨资产配置
- T+1执行机制:信号基于T日数据,T+1日执行
- 溢价控制:跨境ETF溢价过滤
- 持仓跟踪:完整的交易记录和净值贡献计算
问题:
- 调仓逻辑与因子计算耦合
- 缺乏风控模块(止损、仓位管理)
- 单一策略类型,无法扩展其他策略
2.4 报告层设计
优点:
- 完整的KPI指标体系
- 可视化报告:净值曲线、月度收益、盈亏分布、品种排行
- 数据一致性:严格基于回测结果文件
问题:
- 报告与策略耦合
- 缺乏实盘监控接口
三、通用交易系统抽象设计
3.1 核心抽象原则
| 原则 | 说明 |
|---|---|
| 数据独立 | 数据获取与策略逻辑分离,支持多源扩展 |
| 因子可插拔 | 因子计算模块化,支持自定义因子组合 |
| 策略可配置 | 策略逻辑通过配置驱动,无需修改代码 |
| 执行可扩展 | 支持回测、模拟盘、实盘多种执行模式 |
| 风控独立 | 风控模块独立,支持止损、仓位、敞口控制 |
3.2 建议架构设计
trading_system/
├── core/
│ ├── data/
│ │ ├── sources/ # 数据源接口(可插拔)
│ │ │ ├── base.py # 数据源抽象基类
│ │ │ ├── tushare.py
│ │ │ ├── yfinance.py
│ │ │ └── ccxt.py
│ │ ├── router.py # 数据源路由
│ │ └── cache.py # 缓存管理(版本控制)
│ │
│ ├── factors/
│ │ ├── base.py # 因子抽象基类
│ │ ├── registry.py # 因子注册器
│ │ ├── momentum.py
│ │ ├── technical.py
│ │ └── fundamental.py
│ │
│ ├── execution/
│ │ ├── base.py # 执行器抽象基类
│ │ ├── backtest.py # 回测执行器
│ │ ├── simulator.py # 模拟盘执行器
│ │ └── live.py # 实盘执行器
│ │
│ └── risk/
│ │ ├── base.py # 风控抽象基类
│ │ ├── stop_loss.py # 止损控制
│ │ ├── position.py # 仓位控制
│ │ └── exposure.py # 敞口控制
│
├── strategies/
│ ├── base.py # 策略抽象基类
│ ├── registry.py # 策略注册器
│ ├── rotation/ # 轮动策略
│ ├── momentum/ # 动量策略
│ └── screener/ # 篩选策略
│
├── portfolio/
│ ├── manager.py # 持仓管理器
│ ├── tracker.py # 交易跟踪
│ ├── rebalancer.py # 调仓执行器
│
├── report/
│ ├── generator.py # 报告生成器
│ ├── metrics.py # KPI计算
│ └── visualizer.py # 可视化
│
├── config/
│ ├── system.yaml # 系统配置
│ ├── strategies/ # 策略配置
│ │ ├── rotation.yaml
│ │ └── momentum.yaml
│ └── factors/ # 因子配置
│
└── scheduler/
├── engine.py # 调度引擎
├── triggers.py # 触发器(定时、事件)
└── notifier.py # 通知器
3.3 核心接口设计
# ==================== 数据源接口 ====================
class DataSource(ABC):
"""数据源抽象基类"""
@abstractmethod
def fetch(self, code: str, start: str, end: str) -> pd.DataFrame:
"""获取OHLCV数据"""
pass
@abstractmethod
def get_trading_calendar(self, market: str) -> List[datetime]:
"""获取交易日历"""
pass
@abstractmethod
def get_supported_codes(self) -> List[str]:
"""获取支持的代码列表"""
pass
# ==================== 因子接口 ====================
class Factor(ABC):
"""因子抽象基类"""
@abstractmethod
def compute(self, data: pd.DataFrame) -> pd.Series:
"""计算因子值"""
pass
@abstractmethod
def get_name(self) -> str:
"""获取因子名称"""
pass
@property
def params(self) -> dict:
"""因子参数"""
return {}
class FactorRegistry:
"""因子注册器"""
_factors = {}
@classmethod
def register(cls, name: str, factor_cls: Factor):
cls._factors[name] = factor_cls
@classmethod
def get(cls, name: str) -> Factor:
return cls._factors.get(name)
@classmethod
def list(cls) -> List[str]:
return list(cls._factors.keys())
# ==================== 执行器接口 ====================
class Executor(ABC):
"""执行器抽象基类"""
@abstractmethod
def execute(self, signals: pd.DataFrame, portfolio: Portfolio) -> Portfolio:
"""执行信号"""
pass
@abstractmethod
def get_mode(self) -> str:
"""获取执行模式"""
pass
class BacktestExecutor(Executor):
"""回测执行器"""
def execute(self, signals, portfolio):
# 处理调仓成本
# 计算收益率
# 更新净值
pass
def get_mode(self) -> str:
return "backtest"
class LiveExecutor(Executor):
"""实盘执行器"""
def execute(self, signals, portfolio):
# 检查交易权限
# 发送交易指令
# 记录交易结果
pass
def get_mode(self) -> str:
return "live"
# ==================== 风控接口 ====================
class RiskControl(ABC):
"""风控抽象基类"""
@abstractmethod
def check(self, portfolio: Portfolio, signal: Signal) -> bool:
"""风控检查"""
pass
@abstractmethod
def apply(self, portfolio: Portfolio) -> Portfolio:
"""应用风控"""
pass
class StopLossControl(RiskControl):
"""止损控制"""
def __init__(self, threshold: float = 0.05):
self.threshold = threshold
def check(self, portfolio, signal):
# 检查是否触发止损
for position in portfolio.positions:
if position.loss > self.threshold:
return False
return True
def apply(self, portfolio):
# 强制平仓止损
pass
# ==================== 策略接口 ====================
class Strategy(ABC):
"""策略抽象基类"""
@abstractmethod
def generate_signals(self, data: pd.DataFrame) -> pd.DataFrame:
"""生成信号"""
pass
@abstractmethod
def get_name(self) -> str:
"""获取策略名称"""
pass
@abstractmethod
def validate_config(self, config: dict) -> bool:
"""验证配置"""
pass
# ==================== 持仓管理接口 ====================
class Portfolio:
"""持仓管理器"""
def __init__(self):
self.positions = {} # 当前持仓
self.cash = 0.0 # 现金
self.nav = 1.0 # 净值
self.trades = [] # 交易记录
def rebalance(self, target_positions: dict):
"""调仓"""
pass
def get_nav(self) -> float:
"""获取净值"""
pass
def get_positions(self) -> dict:
"""获取持仓"""
return self.positions
3.4 配置驱动设计
# config/strategies/rotation.yaml(通用化后)
# ==================== 基础配置 ====================
strategy:
name: "rotation"
version: "2.0"
mode: "backtest" # backtest | simulator | live
# ==================== 候选池配置 ====================
universe:
type: "static" # static | dynamic
codes:
# ...(与现有配置相同)
mapping:
signal_to_trade: true # 信号源→交易标的映射
# ==================== 因子配置 ====================
factors:
- name: "weighted_momentum"
weight: 1.0
params:
n_days: 25
crash_filter: true
# 可扩展多个因子
# - name: "volatility"
# weight: 0.3
# params:
# period: 20
# ==================== 选股配置 ====================
selection:
mode: "diversified" # top_n | diversified | custom
select_num: 3
group_by: "market" # 按大类分组
top_per_group: 1
# ==================== 调仓配置 ====================
rebalance:
frequency: "daily"
min_holding_days: 1
threshold: 0.0
cost: 0.001
# ==================== 风控配置 ====================
risk:
stop_loss:
enabled: true
threshold: 0.05
position_limit:
max_position: 0.5
max_single: 0.33
premium_control:
enabled: true
threshold: 0.10
# ==================== 执行配置 ====================
execution:
mode: "backtest"
start_date: "2019-01-01"
benchmark: "000300.SH"
# ==================== 数据源配置 ====================
data:
sources:
- name: "tushare"
markets: ["A"]
- name: "yfinance"
markets: ["US", "HK", "JP", "EU"]
proxy:
type: "ssh"
host: "8.218.167.69"
port: 22
四、迁移路径建议
4.1 阶段一:数据层重构
目标:修复ETF列名问题,建立可扩展数据源架构
任务:
- 修复
compute_factors()中的ETF数据路由逻辑 - 创建
DataSource抽象基类 - 统一数据缓存管理(添加版本控制)
4.2 阶段二:因子层抽象
目标:因子计算可插拔、可组合
任务:
- 创建
Factor抽象基类 - 建立
FactorRegistry注册机制 - 支持因子组合和加权
4.3 阶段三:风控模块独立
目标:止损、仓位、敞口控制
任务:
- 创建
RiskControl抽象基类 - 实现止损控制
- 实现仓位限制
4.4 阶段四:执行器分离
目标:支持回测、模拟盘、实盘三种模式
任务:
- 创建
Executor抽象基类 - 实现回测执行器(迁移现有逻辑)
- 实现模拟盘执行器(模拟交易)
- 实现实盘执行器(连接券商API)
4.5 阶段五:配置驱动
目标:策略逻辑通过配置驱动
任务:
- 策略配置YAML重构
- 配置验证机制
- 热加载配置
五、总结与建议
5.1 现有系统评价
| 维度 | 评分 | 说明 |
|---|---|---|
| 数据层 | 3.5/5 | 多源架构优秀,但有列名匹配bug |
| 因子层 | 4/5 | 加权动量设计合理,崩盘过滤有效 |
| 策略层 | 3/5 | 分散化选股创新,但缺乏扩展性 |
| 执行层 | 2/5 | 仅支持回测,缺乏模拟/实盘 |
| 风控层 | 1/5 | 仅溢价控制,缺乏止损/仓位管理 |
| 报告层 | 4.5/5 | KPI完整,可视化丰富 |
5.2 通用化优先级
| 优先级 | 模块 | 紧急程度 | 预估工作量 |
|---|---|---|---|
| P0 | 修复ETF数据路由bug | 🔴紧急 | 0.5天 |
| P1 | 风控模块独立 | 🟡重要 | 2天 |
| P1 | 因子层抽象 | 🟡重要 | 1天 |
| P2 | 数据源可插拔 | 🟢一般 | 2天 |
| P2 | 执行器分离 | 🟢一般 | 3天 |
| P3 | 配置驱动 | 🔵低 | 1天 |
5.3 关键改进建议
- 立即修复:ETF数据列名匹配问题(影响回测真实性)
- 短期改进:添加止损控制(保护实盘资金)
- 中期重构:数据源/因子/执行器抽象(提升扩展性)
- 长期规划:实盘执行器、调度系统(支持自动化运行)
文档版本:V1.0 生成时间:2026-05-08 适用范围:ETF轮动策略系统架构分析与通用化设计