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,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)*