包含4份核心文档: - 轮动策略系统架构分析报告 - 量化策略通用框架抽象设计 - Freqtrade架构调研与对比分析 - ETF轮动策略通用化重构方案 调研结论:三种策略可抽象通用框架 设计决策:因子注册器风格 + 5个核心回调钩子 + TopN/Trend/Reversal信号生成器
535 lines
15 KiB
Markdown
535 lines
15 KiB
Markdown
# 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 策略核心流程
|
||
|
||
```mermaid
|
||
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 核心接口设计
|
||
|
||
```python
|
||
# ==================== 数据源接口 ====================
|
||
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 配置驱动设计
|
||
|
||
```yaml
|
||
# 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列名问题,建立可扩展数据源架构
|
||
|
||
**任务**:
|
||
1. 修复`compute_factors()`中的ETF数据路由逻辑
|
||
2. 创建`DataSource`抽象基类
|
||
3. 统一数据缓存管理(添加版本控制)
|
||
|
||
### 4.2 阶段二:因子层抽象
|
||
|
||
**目标**:因子计算可插拔、可组合
|
||
|
||
**任务**:
|
||
1. 创建`Factor`抽象基类
|
||
2. 建立`FactorRegistry`注册机制
|
||
3. 支持因子组合和加权
|
||
|
||
### 4.3 阶段三:风控模块独立
|
||
|
||
**目标**:止损、仓位、敞口控制
|
||
|
||
**任务**:
|
||
1. 创建`RiskControl`抽象基类
|
||
2. 实现止损控制
|
||
3. 实现仓位限制
|
||
|
||
### 4.4 阶段四:执行器分离
|
||
|
||
**目标**:支持回测、模拟盘、实盘三种模式
|
||
|
||
**任务**:
|
||
1. 创建`Executor`抽象基类
|
||
2. 实现回测执行器(迁移现有逻辑)
|
||
3. 实现模拟盘执行器(模拟交易)
|
||
4. 实现实盘执行器(连接券商API)
|
||
|
||
### 4.5 阶段五:配置驱动
|
||
|
||
**目标**:策略逻辑通过配置驱动
|
||
|
||
**任务**:
|
||
1. 策略配置YAML重构
|
||
2. 配置验证机制
|
||
3. 热加载配置
|
||
|
||
---
|
||
|
||
## 五、总结与建议
|
||
|
||
### 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 关键改进建议
|
||
|
||
1. **立即修复**:ETF数据列名匹配问题(影响回测真实性)
|
||
2. **短期改进**:添加止损控制(保护实盘资金)
|
||
3. **中期重构**:数据源/因子/执行器抽象(提升扩展性)
|
||
4. **长期规划**:实盘执行器、调度系统(支持自动化运行)
|
||
|
||
---
|
||
|
||
*文档版本:V1.0*
|
||
*生成时间:2026-05-08*
|
||
*适用范围:ETF轮动策略系统架构分析与通用化设计* |