docs: 添加策略框架调研与设计方案

包含4份核心文档:
- 轮动策略系统架构分析报告
- 量化策略通用框架抽象设计
- Freqtrade架构调研与对比分析
- ETF轮动策略通用化重构方案

调研结论:三种策略可抽象通用框架
设计决策:因子注册器风格 + 5个核心回调钩子 + TopN/Trend/Reversal信号生成器
This commit is contained in:
2026-05-11 22:17:41 +08:00
parent baeeb13c34
commit c54ba442ad
4 changed files with 2243 additions and 0 deletions

View File

@@ -0,0 +1,387 @@
# ETF轮动策略通用化重构方案
## 一、重构目标与范围
### 1.1 核心目标
**将现有轮动策略重构为通用量化框架**,支持:
- ✅ 轮动策略(动量选股 + Top N
- ✅ 趋势跟踪策略(趋势因子 + 信号跟随)
- ✅ 反转策略(反转因子 + 超买超卖)
- ✅ 自定义策略扩展
### 1.2 重构范围
| 模块 | 是否重构 | 重构内容 | 保持不变 |
|------|----------|----------|----------|
| **数据层** | ✅ 部分重构 | 添加DataSource抽象接口 | 混合数据源逻辑保留 |
| **因子层** | ✅ 重构 | FactorBase抽象 + 注册器 + 组合器 | 因子计算逻辑保留 |
| **信号层** | ✅ 重构 | SignalGenerator抽象TopN/Trend/Reversal | 选股逻辑迁移 |
| **风控层** | ✅ 新增 | 回调钩子 + 风控组件库 | 无(原为分散化) |
| **执行层** | ⚠️ 保持 | 回测引擎不变 | 回测逻辑完整保留 |
| **报告层** | ⚠️ 保持 | KPI计算不变 | 可视化保留 |
| **配置层** | ✅ 重构 | YAML配置驱动 | 参数结构保留 |
---
## 二、核心设计决策(需确认)
### 决策点1因子抽象方式
**选项AFreqtrade风格方法内定义**
```python
def populate_indicators(self, dataframe):
dataframe['momentum'] = calculate_momentum(dataframe, 25)
dataframe['rsi'] = ta.RSI(dataframe, 14)
return dataframe
```
- 优点简单直观与Freqtrade一致
- 缺点:因子不可复用,难以组合
**选项B注册器风格模块化**
```python
class MomentumFactor(FactorBase):
def compute(self, data):
return calculate_momentum(data, self.n_days)
FactorRegistry.register(MomentumFactor)
# 在策略中使用
factors = FactorCombiner([
FactorRegistry.get('momentum', n_days=25),
FactorRegistry.get('volatility', period=20)
])
```
- 优点:因子可复用、可组合、可插拔
- 缺点:复杂度略高
**建议****选择B注册器风格**,保持我们的模块化优势。
---
### 决策点2回调钩子范围
**参考Freqtrade的回调设计**
| 回调钩子 | 用途 | 是否需要 |
|----------|------|----------|
| `before_entry` | 入场前检查(溢价、崩盘) | ✅ 需要 |
| `after_entry` | 入场后记录 | ⚠️ 可选 |
| `before_exit` | 出场前检查 | ⚠️ 可选 |
| `after_exit` | 出场后记录 | ⚠️ 可选 |
| `dynamic_stoploss` | 动态止损 | ✅ 需要 |
| `custom_exit` | 自定义出场条件 | ✅ 需要 |
| `position_adjust` | DCA/部分止盈 | ❌ 不需要(轮动不适用) |
**建议****实现5个核心回调**before_entry, dynamic_stoploss, custom_exit, after_entry, after_exit
---
### 册策点3参数装饰器设计
**Freqtrade风格**
```python
class RotationStrategy:
n_days = IntParameter(10, 60, default=25, space='factor')
select_num = IntParameter(1, 5, default=3, space='signal')
```
**简化风格无Hyperopt**
```python
class RotationStrategy:
n_days = 25 # 类属性,可被配置覆盖
select_num = 3
```
**建议****先实现简化版(类属性 + 配置覆盖)**,后续再添加参数装饰器 + Hyperopt。
---
### 决策点4信号生成抽象
**选项A统一SignalGenerator接口**
```python
class SignalGenerator(ABC):
def generate(self, factor_data: DataFrame) -> DataFrame
class TopNSelector(SignalGenerator):
def generate(self, factor_data):
# Top N选股逻辑
class TrendFollower(SignalGenerator):
def generate(self, factor_data):
# 趋势跟随逻辑
```
**选项B策略直接生成信号**
```python
class RotationStrategy:
def generate_signals(self, data):
# 直接在策略内生成
```
**建议****选择A统一SignalGenerator**,信号逻辑可复用、可插拔。
---
### 决策点5执行模式支持
**Freqtrade支持**backtest / hyperopt / dry / live
**当前系统支持**backtest only
**需要添加**
- ✅ dry-run模拟盘验证策略逻辑
- ⚠️ live实盘需券商API对接
- ❌ hyperopt后期添加
**建议****仅添加dry-run模式**,实盘执行器延后。
---
## 三、分阶段实施路径
### 阶段一因子层抽象P1预估2天
**目标**:因子可插拔、可组合
**实施内容**
1. 创建`FactorBase`抽象基类
2. 创建`FactorRegistry`注册器
3. 创建`FactorCombiner`组合器
4. 重构现有动量因子为`MomentumFactor`
5. 添加技术因子(`TrendFactor`, `ReversalFactor`
**验收标准**
- 因子可注册、可获取、可组合
- 现有轮动策略功能不变(回归测试)
---
### 阶段二信号层抽象P1预估1天
**目标**:信号生成可插拔
**实施内容**
1. 创建`SignalGenerator`抽象基类
2. 创建`TopNSelector`实现(迁移现有选股逻辑)
3. 创建`TrendFollower`实现
4. 创建`ReversalTrader`实现
**验收标准**
- 三种信号生成器可独立运行
- TopNSelector与原逻辑一致
---
### 阶段三回调钩子机制P1预估1天
**目标**:生命周期可控
**实施内容**
1.`StrategyBase`中添加回调钩子定义
2. 实现`before_entry`回调(溢价过滤)
3. 实现`dynamic_stoploss`回调
4. 实现`custom_exit`回调
**验收标准**
- 回调可正常触发
- 溢价过滤生效
- 动态止损生效
---
### 阶段四配置驱动重构P2预估1天
**目标**:策略参数可配置
**实施内容**
1. YAML配置结构设计
2. 配置加载与验证
3. 配置覆盖类属性
4. 策略工厂(根据配置创建策略)
**验收标准**
- 可通过YAML配置运行策略
- 配置可覆盖策略默认参数
---
### 阶段五:趋势/反转策略实现P3预估2-3天
**目标**:验证框架扩展性
**实施内容**
1. 实现`TrendFollowStrategy`
2. 实现`ReversalStrategy`
3. 回测验证
**验收标准**
- 新策略可正常运行
- 回测报告正常生成
---
## 四、预期收益与风险
### 4.1 预期收益
| 维度 | 当前状态 | 重构后 | 提升 |
|------|----------|--------|------|
| **代码复用** | 因子/信号耦合 | 模块化复用 | 50%+ |
| **策略扩展** | 仅轮动策略 | 支持3+策略类型 | - |
| **参数调优** | 手动修改代码 | 配置驱动 | 效率提升 |
| **风控灵活性** | 固定分散化 | 回调动态控制 | - |
| **维护成本** | 多处修改 | 单点修改 | 降低50% |
### 4.2 风险评估
| 风险 | 等级 | 应对措施 |
|------|------|----------|
| **回归风险**:重构导致原有逻辑变化 | 🔴高 | 每阶段完成后运行回测验证 |
| **性能风险**:抽象层增加性能损耗 | 🟡中 | 保持向量化计算,避免循环 |
| **复杂度风险**:抽象层增加理解成本 | 🟡中 | 完善文档 + 示例代码 |
| **时间风险**:预估时间不准 | 🟢低 | 分阶段验收,及时调整 |
---
## 五、关键架构图
### 5.1 最终架构
```
┌─────────────────────────────────────────────────────────────┐
│ QuantStrategyFramework │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ DataSource │ │ FactorLayer │ │ SignalLayer │ │
│ │ │ │ │ │ │ │
│ │ - HybridSrc │ │ - FactorBase │ │ - SignalGen │ │
│ │ - Tushare │ │ - Registry │ │ - TopN │ │
│ │ - YFinance │ │ - Combiner │ │ - Trend │ │
│ │ │ │ │ │ - Reversal │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ StrategyBase │ │ RiskLayer │ │ ExecLayer │ │
│ │ │ │ │ │ │ │
│ │ - populate_* │ │ - Callbacks │ │ - Backtest │ │
│ │ - 回调钩子 │ │ - StopLoss │ │ - DryRun │ │
│ │ │ │ - Position │ │ │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │
├─────────────────────────────────────────────────────────────┤
│ Config (YAML驱动) │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │RotationStrat │ │ TrendStrat │ │ ReversalStrat│ │
│ │ │ │ │ │ │ │
│ │ 动量因子 │ │ 趋势因子 │ │ 反转因子 │ │
│ │ TopN选股 │ │ 趋势跟随 │ │ 反转交易 │ │
│ │ 回调过滤 │ │ 动态止损 │ │ 快速止损 │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
```
### 5.2 因子层设计
```python
# 因子基类
class FactorBase(ABC):
@abstractmethod
def compute(self, data: DataFrame) -> Series
@property
@abstractmethod
def name(self) -> str
# 因子注册
FactorRegistry.register(MomentumFactor)
FactorRegistry.register(TrendFactor)
# 因子组合
factors = FactorCombiner([
FactorRegistry.get('momentum', n_days=25, weight=0.7),
FactorRegistry.get('volatility', period=20, weight=0.3)
])
```
### 5.3 信号层设计
```python
# 信号生成器
class TopNSelector(SignalGenerator):
def generate(self, factor_data):
# 按因子值排序选Top N
class TrendFollower(SignalGenerator):
def generate(self, factor_data):
# 趋势强度 > 阈值 → 入场
class ReversalTrader(SignalGenerator):
def generate(self, factor_data):
# 超买超卖 → 反转信号
```
### 5.4 回调钩子设计
```python
class StrategyBase:
# 入场前回调
def before_entry(self, code: str, price: float, **kwargs) -> bool:
"""可拒绝交易"""
if kwargs.get('premium', 0) > 0.10:
return False
return True
# 动态止损回调
def dynamic_stoploss(self, position: Position) -> float:
"""根据持仓时间调整止损"""
if position.holding_days > 10:
return -0.03
return -0.10
# 自定义出场回调
def custom_exit(self, position: Position) -> bool:
"""反转信号强制出场"""
return False
```
---
## 六、需确认事项清单
| 序号 | 决策点 | 选项 | 建议 | 你的选择 |
|------|--------|------|------|----------|
| 1 | 因子抽象方式 | A:方法内 / B:注册器 | **B** | ? |
| 2 | 回调钩子范围 | 5个 / 7个 / 全部 | **5个核心** | ? |
| 3 | 参数装饰器 | 简化版 / Freqtrade风格 | **先简化版** | ? |
| 4 | 信号生成抽象 | 统一接口 / 策略内生成 | **统一接口** | ? |
| 5 | 执行模式支持 | 仅backtest / +dry-run / +live | **+dry-run** | ? |
| 6 | 实施优先级 | 全部实施 / 分阶段 | **分阶段** | ? |
| 7 | 时间安排 | 立即开始 / 等待确认 | **等待确认** | ? |
---
## 七、下一步行动
**确认方案后,我将开始**
1. 创建`FactorBase`抽象基类
2. 创建`FactorRegistry`注册器
3. 重构现有动量因子
4. 运行回测验证功能不变
**请确认以下内容**
- ✅ 重构范围是否合理
- ✅ 设计决策是否认可
- ✅ 实施路径是否可行
- ✅ 时间安排是否同意
---
*方案版本V1.0*
*生成时间2026-05-08*
*等待用户确认*

View File

@@ -0,0 +1,639 @@
# Freqtrade架构调研与对比分析报告
## 一、Freqtrade架构概览
### 1.1 项目定位
Freqtrade是一个开源的加密货币量化交易框架核心特点
- **成熟度高**2017年开源持续维护社区活跃
- **生产就绪**:支持回测、模拟盘、实盘三种模式
- **配置驱动**:策略、参数、风控均可通过配置控制
- **扩展性强**:支持自定义因子、策略、损失函数、交易所
### 1.2 核心架构图
```
┌─────────────────────────────────────────────────────────────────────┐
│ FreqtradeBot (主控制器) │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Strategy │ │ Exchange │ │ DataProvider │ │
│ │ (IStrategy)│ │ (CCXT) │ │ │ │
│ │ │ │ │ │ │ │
│ │ - 指标计算 │ │ - OHLCV获取 │ │ - 数据缓存 │ │
│ │ - 入场信号 │ │ - 交易执行 │ │ - 实时推送 │ │
│ │ - 出场信号 │ │ - 余额查询 │ │ │ │
│ │ - 回调函数 │ │ │ │ │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Portfolio │ │ RPC/Notify│ │ Hyperopt │ │
│ │ Manager │ │ │ │ (Optuna) │ │
│ │ │ │ - Telegram │ │ │ │
│ │ - 持仓跟踪 │ │ - Discord │ │ - 参数优化 │ │
│ │ - 余额管理 │ │ - WebUI │ │ - 损失函数 │ │
│ │ │ │ │ │ │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │
├─────────────────────────────────────────────────────────────────────┤
│ Configuration (JSON/YAML) │
└─────────────────────────────────────────────────────────────────────┘
```
---
## 二、核心模块设计
### 2.1 策略抽象层IStrategy
**设计理念**:策略是核心,一切围绕策略接口设计
```python
class IStrategy:
"""策略抽象接口"""
# ===== 类属性(配置化参数) =====
INTERFACE_VERSION = 3 # 接口版本控制
timeframe = '5m' # K线周期
can_short = False # 是否允许做空
minimal_roi = { # 最小ROI目标
"0": 0.10, # 立即获利10%
"60": 0.05, # 60分钟后获利5%
}
stoploss = -0.10 # 止损比例
# ===== 核心抽象方法(必须实现) =====
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
"""计算技术指标"""
# 用户自定义指标逻辑
dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14)
dataframe['macd'] = ta.MACD(dataframe)['macd']
return dataframe
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
"""生成入场信号"""
dataframe.loc[
(dataframe['rsi'] < 30) & # 条件组合
(dataframe['macd'] > 0),
'enter_long'
] = 1
return dataframe
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
"""生成出场信号"""
dataframe.loc[
(dataframe['rsi'] > 70),
'exit_long'
] = 1
return dataframe
# ===== 回调函数(可选实现) =====
def confirm_trade_entry(self, pair, order_type, amount, rate, **kwargs) -> bool:
"""入场前确认回调 - 可拒绝交易"""
return True
def custom_stake_amount(self, pair, current_time, current_rate, **kwargs) -> float:
"""动态仓位调整"""
return self.stake_amount
def custom_stoploss(self, pair, trade, current_time, current_rate, **kwargs) -> float:
"""动态止损"""
return self.stoploss
def custom_exit(self, pair, trade, current_time, current_rate, **kwargs) -> bool:
"""自定义出场条件"""
return False
def adjust_trade_position(self, pair, trade, current_time, current_rate, **kwargs) -> float:
"""动态仓位调整DCA/部分止盈)"""
return None
```
**关键设计点**
| 设计点 | 说明 | 优势 |
|--------|------|------|
| **接口版本控制** | `INTERFACE_VERSION` | 向后兼容,平滑升级 |
| **类属性配置** | `timeframe`, `stoploss` | 参数可从配置文件覆盖 |
| **DataFrame驱动** | 所有计算基于DataFrame | 向量化计算,高性能 |
| **回调钩子** | 多生命周期钩子 | 灵活控制交易细节 |
| **信号列名约定** | `enter_long`, `exit_long` | 统一信号格式 |
### 2.2 数据层抽象Exchange + DataProvider
**Exchange接口**基于CCXT库统一封装100+交易所
```python
class Exchange:
"""交易所抽象基于CCXT"""
def __init__(self, config: dict):
# 初始化CCXT交易所实例
self._api = ccxt.binance({
'apiKey': config['key'],
'secret': config['secret'],
'enableRateLimit': True,
})
# ===== 数据获取 =====
def fetch_ohlcv(self, pair: str, timeframe: str, since: int) -> List:
"""获取K线数据"""
return self._api.fetch_ohlcv(pair, timeframe, since)
def fetch_ticker(self, pair: str) -> dict:
"""获取行情"""
return self._api.fetch_ticker(pair)
def fetch_order_book(self, pair: str, limit: int) -> dict:
"""获取订单簿"""
return self._api.fetch_order_book(pair, limit)
# ===== 交易执行 =====
def create_order(self, pair: str, type: str, side: str, amount: float, price: float) -> dict:
"""创建订单"""
return self._api.create_order(pair, type, side, amount, price)
def cancel_order(self, order_id: str, pair: str) -> dict:
"""取消订单"""
return self._api.cancel_order(order_id, pair)
# ===== 账户查询 =====
def fetch_balance(self) -> dict:
"""查询余额"""
return self._api.fetch_balance()
def fetch_orders(self, pair: str) -> List:
"""查询订单"""
return self._api.fetch_orders(pair)
```
**DataProvider**:数据缓存与统一访问
```python
class DataProvider:
"""数据提供者 - 缓存管理"""
def __init__(self, exchange: Exchange, config: dict):
self._exchange = exchange
self._cached_pairs = {}
def ohlcv(self, pair: str, timeframe: str, since: int) -> DataFrame:
"""获取K线数据带缓存"""
cache_key = f"{pair}_{timeframe}"
if cache_key not in self._cached_pairs:
# 从交易所获取
data = self._exchange.fetch_ohlcv(pair, timeframe, since)
# 转换为DataFrame
df = pd.DataFrame(data, columns=['date', 'open', 'high', 'low', 'close', 'volume'])
self._cached_pairs[cache_key] = df
return self._cached_pairs[cache_key]
def refresh(self, pair: str, timeframe: str):
"""刷新缓存"""
# 只更新最新数据,不重新下载全部
pass
```
### 2.3 配置驱动设计
**配置层级**
```json
{
// 系统配置
"max_open_trades": 3,
"stake_currency": "USDT",
"stake_amount": "unlimited",
"dry_run": true,
"dry_run_wallet": 1000,
// 交易所配置
"exchange": {
"name": "binance",
"key": "your_key",
"secret": "your_secret",
"ccxt_config": {
"enableRateLimit": true
},
"pair_whitelist": ["BTC/USDT", "ETH/USDT"],
"pair_blacklist": ["BNB/USDT"]
},
// 策略配置(可覆盖策略类属性)
"strategy": "SampleStrategy",
"timeframe": "5m",
"minimal_roi": {
"0": 0.10
},
"stoploss": -0.10,
// 通知配置
"telegram": {
"enabled": true,
"token": "your_token",
"chat_id": "your_chat_id"
}
}
```
**配置优先级**
```
命令行参数 > 环境变量 > 配置文件 > 策略默认值
```
### 2.4 Hyperopt参数优化
**参数定义**(在策略中):
```python
class MyStrategy(IStrategy):
# 定义可优化参数
buy_rsi = IntParameter(10, 40, default=30, space='buy')
sell_rsi = IntParameter(60, 90, default=70, space='sell')
stoploss = DecimalParameter(-0.05, -0.20, default=-0.10, space='stoploss')
def populate_entry_trend(self, dataframe, metadata):
dataframe.loc[
(dataframe['rsi'] < self.buy_rsi.value), # 使用参数
'enter_long'
] = 1
return dataframe
```
**优化空间**
- `buy` / `enter`: 入场参数
- `sell` / `exit`: 出场参数
- `roi`: ROI表优化
- `stoploss`: 止损优化
- `trailing`: 跟踪止损优化
- `protection`: 保护策略优化
**损失函数**
```python
class SharpeHyperOptLoss(IHyperOptLoss):
"""Sharpe比率损失函数"""
@staticmethod
def hyperopt_loss_function(results, trade_count, min_date, max_date, *args) -> float:
# 计算Sharpe比率
returns = results['profit_ratio']
sharpe = returns.mean() / returns.std() * np.sqrt(365)
return -sharpe # 返回负值(优化最大化)
```
---
## 三、Freqtrade设计优势
### 3.1 核心设计亮点
| 设计点 | Freqtrade实现 | 优势 |
|--------|---------------|------|
| **策略接口** | `IStrategy`抽象类 + 回调钩子 | 灵活度高,生命周期完整 |
| **数据抽象** | CCXT统一封装100+交易所 | 数据源可插拔 |
| **配置驱动** | JSON配置 + 参数覆盖 | 无需修改代码即可调整 |
| **参数优化** | Optuna集成 + 参数装饰器 | 自动化参数搜索 |
| **执行模式** | backtest/dry/live统一接口 | 平滑切换 |
| **风控回调** | `custom_stoploss`, `custom_exit` | 灵活风控逻辑 |
### 3.2 向量化设计
**DataFrame驱动**
- 所有指标计算基于DataFrame
- 避免`iloc[-1]`,使用`shift()`
- 批量计算,高性能
- 防止前视偏差lookahead bias
```python
# 错误使用iloc可能引入前视偏差
if dataframe['rsi'].iloc[-1] > 70:
dataframe['exit_long'] = 1
# 正确使用shift()
dataframe.loc[
(dataframe['rsi'].shift(1) > 70), # 使用前一周期数据
'exit_long'
] = 1
```
---
## 四、与我们的框架对比
### 4.1 设计差异对比
| 维度 | Freqtrade | 我们的框架 | 建议 |
|------|-----------|------------|------|
| **策略接口** | `IStrategy`类 + 回调钩子 | 配置驱动策略模式 | **借鉴回调钩子设计** |
| **因子层** | `populate_indicators`方法内定义 | `FactorBase`抽象 + 注册器 | **我们的设计更模块化** |
| **信号层** | `populate_entry_trend/exit_trend` | `SignalGenerator`抽象 | **两者设计相似** |
| **数据层** | CCXT统一封装 | 混合数据源Tushare + YFinance | **借鉴交易所抽象接口** |
| **风控层** | 回调函数(`custom_stoploss` | 风控组件库 | **回调更灵活,组件更复用** |
| **配置驱动** | JSON配置 + 类属性覆盖 | YAML配置 | **两者相似** |
| **参数优化** | Optuna集成 + 参数装饰器 | 无 | **需要添加Hyperopt模块** |
### 4.2 可借鉴设计
#### 1回调钩子机制
```python
# Freqtrade的回调设计
class IStrategy:
def confirm_trade_entry(self, pair, order_type, amount, rate, **kwargs) -> bool:
"""入场前确认 - 可拒绝交易"""
# 检查溢价率、市场状态等
if self.check_premium(pair) > 0.10:
return False # 拒绝交易
return True
def custom_stoploss(self, pair, trade, current_time, current_rate, **kwargs) -> float:
"""动态止损"""
# 根据持仓时间调整止损
if trade.open_date < current_time - timedelta(days=5):
return -0.05 # 5天后收紧止损
return -0.10
def custom_exit(self, pair, trade, current_time, current_rate, **kwargs) -> bool:
"""自定义出场条件"""
# 检查市场反转信号
if self.detect_reversal(pair):
return True # 强制出场
return False
```
**借鉴方案**
```python
class StrategyBase:
"""我们的策略基类 + 回调钩子"""
# 入场回调
def before_entry(self, code: str, price: float, **kwargs) -> bool:
"""入场前检查(溢价率、崩盘检测)"""
return True
def after_entry(self, trade: Trade, **kwargs):
"""入场后记录"""
pass
# 出场回调
def before_exit(self, trade: Trade, **kwargs) -> bool:
"""出场前检查"""
return True
def after_exit(self, trade: Trade, **kwargs):
"""出场后记录"""
pass
# 风控回调
def dynamic_stoploss(self, position: Position, **kwargs) -> float:
"""动态止损"""
return self.config.get('stoploss', -0.05)
def position_adjust(self, portfolio: Portfolio, **kwargs) -> dict:
"""仓位调整DCA/部分止盈)"""
return {}
```
#### 2参数装饰器
```python
# Freqtrade的参数装饰器
from freqtrade.strategy import IntParameter, DecimalParameter, CategoricalParameter
class MyStrategy(IStrategy):
# 可优化参数定义
buy_rsi_threshold = IntParameter(10, 40, default=30, space='buy', optimize=True)
sell_rsi_threshold = IntParameter(60, 90, default=70, space='sell', optimize=True)
timeframe = CategoricalParameter(['1m', '5m', '15m'], default='5m', space='buy')
```
**借鉴方案**
```python
# 我们的参数装饰器设计
class Parameter:
"""参数基类"""
def __init__(self, low, high, default, space='default', optimize=True):
self.low = low
self.high = high
self.default = default
self.space = space
self.optimize = optimize
self._value = default
def __get__(self, obj, objtype):
return self._value
def __set__(self, obj, value):
self._value = value
class IntParameter(Parameter):
"""整数参数"""
pass
class FloatParameter(Parameter):
"""浮点参数"""
pass
# 使用示例
class RotationStrategy(StrategyBase):
n_days = IntParameter(10, 60, default=25, space='factor')
select_num = IntParameter(1, 5, default=3, space='signal')
stoploss = FloatParameter(0.01, 0.10, default=0.05, space='risk')
```
#### 3接口版本控制
```python
# Freqtrade的接口版本
class IStrategy:
INTERFACE_VERSION = 3 # 当前版本
# 不同版本的参数命名不同
# v2: buy, sell
# v3: enter_long, exit_long
```
**借鉴方案**
```python
class StrategyBase:
"""策略基类 + 版本控制"""
INTERFACE_VERSION = 1
@classmethod
def validate_version(cls, config: dict) -> bool:
"""验证配置与版本匹配"""
if config.get('version', 1) != cls.INTERFACE_VERSION:
raise ValueError(f"Strategy version mismatch")
return True
```
---
## 五、融合设计方案
### 5.1 最佳实践融合
**融合Freqtrade优势 + 我们的模块化设计**
```python
class QuantStrategy(StrategyBase):
"""量化策略基类 - 融合设计"""
INTERFACE_VERSION = 1
# ===== 类属性(配置可覆盖) =====
timeframe = '1d'
select_num = 3
stoploss = -0.05
# ===== 可优化参数(装饰器) =====
n_days = IntParameter(10, 60, default=25, space='factor')
# ===== 因子模块(模块化) =====
def init_factors(self) -> FactorCombiner:
"""初始化因子组合"""
factors = [
FactorRegistry.get('momentum', n_days=self.n_days.value),
FactorRegistry.get('volatility', period=20),
]
return FactorCombiner(factors, weights=[0.7, 0.3])
# ===== 核心方法(必须实现) =====
def populate_indicators(self, data: DataFrame, metadata: dict) -> DataFrame:
"""计算因子"""
factor_values = self._factors.compute(data)
data = pd.concat([data, factor_values], axis=1)
return data
def generate_signals(self, data: DataFrame, metadata: dict) -> DataFrame:
"""生成信号"""
return self._signal_gen.generate(data)
# ===== 回调钩子(可选实现) =====
def before_entry(self, code: str, price: float, **kwargs) -> bool:
"""入场前检查"""
# 溢价率过滤
if kwargs.get('premium', 0) > 0.10:
print(f"溢价过高,拒绝入场: {code}")
return False
# 崩盘检测
if self._detect_crash(code):
return False
return True
def dynamic_stoploss(self, position: Position, **kwargs) -> float:
"""动态止损"""
# 持仓时间越长,止损越紧
holding_days = position.holding_days
if holding_days > 10:
return -0.03 # 10天后收紧止损
elif holding_days > 5:
return -0.05
return -0.10
def custom_exit(self, position: Position, **kwargs) -> bool:
"""自定义出场"""
# 反转信号检测
if self._detect_reversal(position.code):
return True
return False
```
### 5.2 配置驱动融合
```yaml
# config/strategies/rotation.yaml融合设计
strategy:
name: "rotation"
version: 1
# 参数(可覆盖类属性)
parameters:
n_days: 25 # 可优化参数
select_num: 3
stoploss: -0.05
# 因子配置
factors:
- name: "momentum"
weight: 0.7
params:
n_days: "${n_days}" # 引用参数
- name: "volatility"
weight: 0.3
# 信号配置
signal:
mode: "top_n"
select_num: "${select_num}"
group_by: "market"
# 回调配置
callbacks:
before_entry:
- type: "premium_filter"
threshold: 0.10
- type: "crash_filter"
dynamic_stoploss:
enabled: true
schedule:
- days: 5
stoploss: -0.05
- days: 10
stoploss: -0.03
# Hyperopt配置
hyperopt:
enabled: true
spaces: ["factor", "signal"]
loss: "SharpeLoss"
epochs: 100
```
---
## 六、总结与建议
### 6.1 Freqtrade设计精髓
| 设计精髓 | 说明 |
|----------|------|
| **策略为中心** | 所有模块围绕`IStrategy`接口设计 |
| **回调钩子** | 生命周期完整控制,灵活度高 |
| **配置覆盖** | 类属性 → 配置文件 → 命令行 |
| **参数装饰器** | 声明式参数定义,自动优化 |
| **向量化计算** | DataFrame驱动高性能 + 防前视偏差 |
| **接口版本** | 平滑升级,向后兼容 |
### 6.2 建议借鉴内容
| 优先级 | 借鉴内容 | 预估工作量 |
|--------|----------|------------|
| **P1** | 回调钩子机制(`before_entry`, `custom_stoploss` | 1天 |
| **P1** | 参数装饰器(`IntParameter`, `FloatParameter` | 1天 |
| **P2** | 接口版本控制 | 0.5天 |
| **P2** | Hyperopt模块Optuna集成 | 2天 |
| **P3** | DataFrame向量化检查工具 | 1天 |
### 6.3 保持我们优势
| 我们的设计优势 | 说明 |
|----------------|------|
| **因子模块化** | `FactorBase` + `FactorRegistry` 更易于复用 |
| **信号模式** | `SignalGenerator` 抽象更清晰 |
| **风控组件库** | 组件化设计更易于组合 |
| **混合数据源** | Tushare + YFinance 跨市场支持 |
---
*文档版本V1.0*
*调研时间2026-05-08*
*参考项目Freqtrade (freqtrade/freqtrade)*

View File

@@ -0,0 +1,535 @@
# 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轮动策略系统架构分析与通用化设计*

View File

@@ -0,0 +1,682 @@
# 量化策略通用框架抽象设计
## 一、三种策略核心能力对比
| 能力维度 | 轮动策略 | 趋势跟踪策略 | 反转策略 |
|----------|----------|--------------|----------|
| **核心逻辑** | 动量排序选出Top N持有 | 识别趋势方向,顺势交易 | 识别超买超卖,逆势交易 |
| **因子类型** | 动量因子、加权动量 | 趋势指标均线、MACD、通道 | 反转指标RSI、KDJ、布林带 |
| **信号频率** | 定期调仓(每日/每周) | 趋势变化时调仓 | 反转点入场 |
| **持仓周期** | 中短期1-30天 | 中长期(数周/数月) | 短期(数天) |
| **持仓数量** | 多标的Top 3-5 | 单一或少数标的 | 单一标的 |
| **风险控制** | 分散化、溢价过滤 | 止损、趋势跟踪止损 | 止损、仓位控制 |
| **执行方式** | T+1执行 | 信号当日或次日执行 | 反转点当日执行 |
---
## 二、通用能力抽象
### 2.1 共性能力矩阵
| 能力层 | 具体能力 | 轮动策略 | 趋势策略 | 反转策略 | 通用化程度 |
|--------|----------|----------|----------|----------|------------|
| **数据层** | 多源数据获取 | ✓ | ✓ | ✓ | **100%** |
| | 交易日历对齐 | ✓ | ✓ | ✓ | **100%** |
| | 缓存管理 | ✓ | ✓ | ✓ | **100%** |
| **因子层** | 因子计算接口 | ✓ | ✓ | ✓ | **100%** |
| | 因子组合/加权 | ✓ | ✓ | ✓ | **100%** |
| | 因子参数化 | ✓ | ✓ | ✓ | **100%** |
| **信号层** | 信号生成接口 | ✓ | ✓ | ✓ | **100%** |
| | 信号过滤机制 | ✓ | ✓ | ✓ | **100%** |
| | 信号强度评估 | 部分 | ✓ | ✓ | **80%** |
| **执行层** | 回测执行器 | ✓ | ✓ | ✓ | **100%** |
| | 模拟盘执行器 | ✓ | ✓ | ✓ | **100%** |
| | 实盘执行器 | ✓ | ✓ | ✓ | **100%** |
| **风控层** | 止损控制 | 部分 | ✓ | ✓ | **100%** |
| | 仓位控制 | ✓ | ✓ | ✓ | **100%** |
| | 敞口控制 | ✓ | ✓ | ✓ | **100%** |
| **报告层** | KPI计算 | ✓ | ✓ | ✓ | **100%** |
| | 可视化报告 | ✓ | ✓ | ✓ | **100%** |
### 2.2 策略差异抽象
| 差异维度 | 轮动策略 | 趋势策略 | 反转策略 | 抽象方式 |
|----------|----------|----------|----------|----------|
| **选股逻辑** | Top N排序 | 趋势强度排序 | 反转信号强度 | **SelectionMode配置** |
| **入场信号** | 动量得分高 | 趋势向上突破 | 反转点确认 | **EntryRule配置** |
| **出场信号** | 动量排名下降 | 趋势反转/止损 | 反转失败/止损 | **ExitRule配置** |
| **持仓数量** | 3-5只 | 1-3只 | 1只 | **select_num配置** |
| **调仓频率** | 每日/定期 | 趋势变化时 | 反转点时 | **RebalanceFrequency配置** |
---
## 三、通用框架设计
### 3.1 核心架构
```
┌─────────────────────────────────────────────────────────────┐
│ QuantStrategyFramework │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ DataLayer │ │ FactorLayer │ │ SignalLayer │ │
│ │ │ │ │ │ │ │
│ │ - DataSource │ │ - FactorBase │ │ - SignalGen │ │
│ │ - Router │ │ - Registry │ │ - Filter │ │
│ │ - Cache │ │ - Combiner │ │ - Validator │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ ExecutionLayer│ │ RiskLayer │ │ ReportLayer │ │
│ │ │ │ │ │ │ │
│ │ - Executor │ │ - RiskCtrl │ │ - Generator │ │
│ │ - Portfolio │ │ - StopLoss │ │ - Metrics │ │
│ │ - Tracker │ │ - Position │ │ - Visualizer │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │
├─────────────────────────────────────────────────────────────┤
│ StrategyConfig (YAML) │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ RotationStrat│ │ TrendStrat │ │ ReversalStrat│ │
│ │ │ │ │ │ │ │
│ │ 动量因子 │ │ 趋势因子 │ │ 反转因子 │ │
│ │ Top N选股 │ │ 趋势跟随 │ │ 反转交易 │ │
│ │ 定期调仓 │ │ 趋势止损 │ │ 快速止损 │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
```
### 3.2 核心抽象接口
```python
# ==================== 因子抽象 ====================
class FactorBase(ABC):
"""因子抽象基类 - 所有策略的因子都继承此接口"""
@abstractmethod
def compute(self, data: pd.DataFrame) -> pd.Series:
"""计算因子值序列"""
pass
@property
@abstractmethod
def name(self) -> str:
"""因子名称"""
pass
@property
def params(self) -> dict:
"""因子参数(可配置)"""
return {}
def validate(self, data: pd.DataFrame) -> bool:
"""验证数据是否满足计算要求"""
return len(data) >= self.params.get('min_periods', 20)
class MomentumFactor(FactorBase):
"""动量因子 - 用于轮动策略"""
def __init__(self, n_days: int = 25, weighted: bool = True):
self._n_days = n_days
self._weighted = weighted
def compute(self, data):
if self._weighted:
# 加权动量得分
return self._weighted_momentum(data['close'], self._n_days)
else:
# 简单动量
return data['close'].pct_change(self._n_days)
@property
def name(self):
return "momentum" if not self._weighted else "weighted_momentum"
@property
def params(self):
return {'n_days': self._n_days, 'weighted': self._weighted}
class TrendFactor(FactorBase):
"""趋势因子 - 用于趋势跟踪策略"""
def __init__(self, method: str = 'ma_cross', fast: int = 5, slow: int = 20):
self._method = method
self._fast = fast
self._slow = slow
def compute(self, data):
if self._method == 'ma_cross':
fast_ma = data['close'].rolling(self._fast).mean()
slow_ma = data['close'].rolling(self._slow).mean()
# 趋势强度 = 快线/慢线偏离度
return (fast_ma - slow_ma) / slow_ma
elif self._method == 'macd':
# MACD趋势强度
return self._compute_macd(data['close'])
@property
def name(self):
return f"trend_{self._method}"
@property
def params(self):
return {'method': self._method, 'fast': self._fast, 'slow': self._slow}
class ReversalFactor(FactorBase):
"""反转因子 - 用于反转策略"""
def __init__(self, method: str = 'rsi', period: int = 14):
self._method = method
self._period = period
def compute(self, data):
if self._method == 'rsi':
# RSI反转信号RSI偏离度
rsi = self._compute_rsi(data['close'], self._period)
# 超买超卖偏离度
return np.where(rsi > 70, -(rsi - 70)/30, # 超买→负值(反转向下)
np.where(rsi < 30, (30 - rsi)/30, # 超卖→正值(反转向上)
0))
elif self._method == 'kdj':
return self._compute_kdj(data)
@property
def name(self):
return f"reversal_{self._method}"
@property
def params(self):
return {'method': self._method, 'period': self._period}
# ==================== 因子注册器 ====================
class FactorRegistry:
"""因子注册器 - 支持动态注册和组合"""
_factors = {}
@classmethod
def register(cls, factor_cls: FactorBase):
"""注册因子"""
instance = factor_cls()
cls._factors[instance.name] = factor_cls
@classmethod
def get(cls, name: str, **params) -> FactorBase:
"""获取因子实例"""
factor_cls = cls._factors.get(name)
if factor_cls:
return factor_cls(**params)
raise ValueError(f"Unknown factor: {name}")
@classmethod
def list(cls) -> List[str]:
"""列出所有注册因子"""
return list(cls._factors.keys())
class FactorCombiner:
"""因子组合器 - 支持多因子加权"""
def __init__(self, factors: List[FactorBase], weights: List[float] = None):
self._factors = factors
self._weights = weights or [1.0] * len(factors)
def compute(self, data: pd.DataFrame) -> pd.Series:
"""计算组合因子值"""
results = []
for factor, weight in zip(self._factors, self._weights):
factor_values = factor.compute(data)
results.append(factor_values * weight)
# 加权平均
return pd.concat(results, axis=1).sum(axis=1)
# ==================== 信号生成抽象 ====================
class SignalGenerator(ABC):
"""信号生成器抽象基类"""
@abstractmethod
def generate(self, factor_values: pd.DataFrame) -> pd.DataFrame:
"""生成交易信号"""
pass
@property
@abstractmethod
def mode(self) -> str:
"""信号生成模式"""
pass
class TopNSelector(SignalGenerator):
"""Top N选股器 - 用于轮动策略"""
def __init__(self, select_num: int = 3, group_by: str = None):
self._select_num = select_num
self._group_by = group_by
def generate(self, factor_values):
# 按因子值排序
if self._group_by:
# 分组选股每大类选Top1再全局选Top3
return self._grouped_selection(factor_values)
else:
# 全局Top N
return self._global_top_n(factor_values)
@property
def mode(self):
return "rotation_top_n"
class TrendFollower(SignalGenerator):
"""趋势跟随器 - 用于趋势跟踪策略"""
def __init__(self, entry_threshold: float = 0.02, exit_threshold: float = -0.02):
self._entry_threshold = entry_threshold
self._exit_threshold = exit_threshold
def generate(self, factor_values):
# 趋势强度 > 阈值 → 入场
# 趋势强度 < 阈值 → 出场
signals = pd.DataFrame(index=factor_values.index)
for code in factor_values.columns:
trend_strength = factor_values[code]
signals[code + '_entry'] = trend_strength > self._entry_threshold
signals[code + '_exit'] = trend_strength < self._exit_threshold
return signals
@property
def mode(self):
return "trend_follow"
class ReversalTrader(SignalGenerator):
"""反转交易器 - 用于反转策略"""
def __init__(self, overbought: float = 70, oversold: float = 30):
self._overbought = overbought
self._oversold = oversold
def generate(self, factor_values):
# 超买区域 → 反转向下信号
# 超卖区域 → 反转向上信号
signals = pd.DataFrame(index=factor_values.index)
for code in factor_values.columns:
reversal_signal = factor_values[code]
# 正值 → 反转向上(买入)
signals[code + '_buy'] = reversal_signal > 0
# 负值 → 反转向下(卖出)
signals[code + '_sell'] = reversal_signal < 0
return signals
@property
def mode(self):
return "reversal"
# ==================== 策略抽象 ====================
class StrategyBase(ABC):
"""策略抽象基类 - 所有策略的核心接口"""
@abstractmethod
def run(self, data: pd.DataFrame) -> pd.DataFrame:
"""运行策略"""
pass
@property
@abstractmethod
def name(self) -> str:
"""策略名称"""
pass
@property
def config(self) -> dict:
"""策略配置"""
return {}
def validate_config(self) -> bool:
"""验证配置有效性"""
return True
class QuantStrategy(StrategyBase):
"""量化策略通用实现 - 配置驱动"""
def __init__(self, config: dict):
self._config = config
# 初始化因子
self._factors = self._init_factors()
# 初始化信号生成器
self._signal_gen = self._init_signal_generator()
# 初始化风控
self._risk_ctrls = self._init_risk_controls()
def _init_factors(self) -> FactorCombiner:
"""根据配置初始化因子组合"""
factor_configs = self._config.get('factors', [])
factors = []
weights = []
for fc in factor_configs:
factor = FactorRegistry.get(fc['name'], **fc.get('params', {}))
factors.append(factor)
weights.append(fc.get('weight', 1.0))
return FactorCombiner(factors, weights)
def _init_signal_generator(self) -> SignalGenerator:
"""根据配置初始化信号生成器"""
signal_config = self._config.get('signal', {})
mode = signal_config.get('mode', 'top_n')
if mode == 'top_n':
return TopNSelector(
select_num=signal_config.get('select_num', 3),
group_by=signal_config.get('group_by')
)
elif mode == 'trend_follow':
return TrendFollower(
entry_threshold=signal_config.get('entry_threshold', 0.02),
exit_threshold=signal_config.get('exit_threshold', -0.02)
)
elif mode == 'reversal':
return ReversalTrader(
overbought=signal_config.get('overbought', 70),
oversold=signal_config.get('oversold', 30)
)
else:
raise ValueError(f"Unknown signal mode: {mode}")
def _init_risk_controls(self) -> List[RiskControl]:
"""根据配置初始化风控"""
risk_configs = self._config.get('risk', [])
controls = []
for rc in risk_configs:
if rc['type'] == 'stop_loss':
controls.append(StopLossControl(threshold=rc.get('threshold', 0.05)))
elif rc['type'] == 'position_limit':
controls.append(PositionLimitControl(
max_position=rc.get('max_position', 0.33)
))
return controls
def run(self, data: pd.DataFrame) -> pd.DataFrame:
"""执行策略"""
# 1. 计算因子
factor_values = self._factors.compute(data)
# 2. 生成信号
signals = self._signal_gen.generate(factor_values)
# 3. 应用风控
for risk_ctrl in self._risk_ctrls:
signals = risk_ctrl.apply(signals)
return signals
@property
def name(self):
return self._config.get('name', 'unknown')
@property
def config(self):
return self._config
```
---
## 四、三种策略配置化实现
### 4.1 轮动策略配置
```yaml
# config/strategies/rotation.yaml
strategy:
name: "rotation"
type: "rotation"
# 因子配置
factors:
- name: "weighted_momentum"
weight: 1.0
params:
n_days: 25
crash_filter: true
# 信号配置
signal:
mode: "top_n" # Top N选股
select_num: 3
group_by: "market" # 按大类分组
# 调仓配置
rebalance:
frequency: "daily"
min_holding_days: 1
cost: 0.001
# 风控配置
risk:
- type: "position_limit"
max_position: 0.33 # 单品种最大仓位
# 执行配置
execution:
mode: "backtest"
start_date: "2019-01-01"
benchmark: "000300.SH"
```
### 4.2 趋势跟踪策略配置
```yaml
# config/strategies/trend_follow.yaml
strategy:
name: "trend_follow"
type: "trend"
# 因子配置
factors:
- name: "trend_ma_cross"
weight: 0.7
params:
fast: 5
slow: 20
- name: "trend_macd"
weight: 0.3
params:
fast: 12
slow: 26
# 信号配置
signal:
mode: "trend_follow"
entry_threshold: 0.02 # 趋势强度 > 2% 入场
exit_threshold: -0.02 # 趋势强度 < -2% 出场
# 持仓配置
position:
max_holdings: 1 # 单标的持仓
# 风控配置
risk:
- type: "stop_loss"
threshold: 0.05 # 5%止损
- type: "trailing_stop"
threshold: 0.03 # 3%跟踪止损
# 执行配置
execution:
mode: "backtest"
start_date: "2020-01-01"
```
### 4.3 反转策略配置
```yaml
# config/strategies/reversal.yaml
strategy:
name: "reversal"
type: "reversal"
# 因子配置
factors:
- name: "reversal_rsi"
weight: 0.6
params:
period: 14
- name: "reversal_kdj"
weight: 0.4
params:
period: 9
# 信号配置
signal:
mode: "reversal"
overbought: 70 # 超买阈值
oversold: 30 # 超卖阈值
# 持仓配置
position:
max_holdings: 1
holding_period: 5 # 最大持仓天数
# 风控配置
risk:
- type: "stop_loss"
threshold: 0.03 # 3%快速止损
- type: "time_stop"
max_days: 5 # 5天内必须出场
# 执行配置
execution:
mode: "backtest"
start_date: "2020-01-01"
```
---
## 五、通用框架优势
### 5.1 代码复用率
| 模块 | 原实现(各策略独立) | 通用框架 | 复用率提升 |
|------|---------------------|----------|------------|
| 数据层 | 3套独立实现 | 1套通用实现 | **67%** |
| 因子层 | 3套因子代码 | 因子注册+组合 | **50%** |
| 信号层 | 3套信号逻辑 | 3种SignalGenerator | **33%** |
| 执行层 | 3套回测引擎 | 1套Executor | **67%** |
| 风控层 | 3套风控逻辑 | 风控组件库 | **67%** |
| 报告层 | 3套报告代码 | 1套报告生成 | **67%** |
### 5.2 扩展能力
**通用框架支持**
- 新因子类型:只需继承`FactorBase`并注册
- 新信号逻辑:只需继承`SignalGenerator`
- 新风控组件:只需继承`RiskControl`
- 新策略类型:只需编写配置文件
**示例:添加新因子**
```python
# 新因子只需继承FactorBase
class VolatilityFactor(FactorBase):
"""波动率因子"""
def __init__(self, period: int = 20):
self._period = period
def compute(self, data):
return data['close'].rolling(self._period).std()
@property
def name(self):
return "volatility"
# 注册因子
FactorRegistry.register(VolatilityFactor)
# 在配置中使用
factors:
- name: "volatility"
weight: 0.2
params:
period: 20
```
---
## 六、实施建议
### 6.1 分阶段实施
| 阶段 | 任务 | 预估工作量 | 优先级 |
|------|------|------------|--------|
| **阶段一** | 因子层抽象 + 注册器 | 1-2天 | P1 |
| **阶段二** | 信号生成器抽象 | 1天 | P1 |
| **阶段三** | 风控模块独立 | 1天 | P2 |
| **阶段四** | 策略配置驱动 | 1天 | P2 |
| **阶段五** | 趋势/反转策略实现 | 2-3天 | P3 |
### 6.2 立即可实施
**现有轮动策略重构路径**
1.`momentum.py`中的因子计算封装为`MomentumFactor`
2. 创建`FactorRegistry`注册动量因子
3. 将选股逻辑封装为`TopNSelector`
4. 将风控逻辑封装为风险控制组件
5. 通过配置驱动运行策略
---
## 七、总结
### 7.1 可抽象程度评估
| 策略类型 | 可抽象比例 | 说明 |
|----------|------------|------|
| **轮动策略** | **85%** | 因子计算、选股、执行、报告均可通用化 |
| **趋势跟踪** | **80%** | 因子不同,但信号生成、执行、风控可通用 |
| **反转策略** | **75%** | 因子差异较大,风控需求更强,其他可通用 |
### 7.2 核心结论
**✅ 三种策略可以抽象出通用框架**,核心设计:
1. **因子层**:抽象接口 + 注册器 + 组合器
2. **信号层**策略模式Strategy Pattern
3. **风控层**:组件化风控库
4. **配置驱动**YAML定义策略参数
**通用化收益**
- 代码复用率提升50%-67%
- 新策略开发时间缩短50%
- 因子/风控组件可跨策略共享
- 维护成本大幅降低
---
*文档版本V1.0*
*生成时间2026-05-08*
*适用范围:量化策略通用框架设计*