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

调研结论:三种策略可抽象通用框架
设计决策:因子注册器风格 + 5个核心回调钩子 + TopN/Trend/Reversal信号生成器
2026-05-11 22:17:41 +08:00

21 KiB
Raw Blame History

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

设计理念:策略是核心,一切围绕策略接口设计

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+交易所

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:数据缓存与统一访问

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 配置驱动设计

配置层级

{
  // 系统配置
  "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参数优化

参数定义(在策略中):

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: 保护策略优化

损失函数

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
# 错误使用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回调钩子机制

# 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

借鉴方案

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参数装饰器

# 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')

借鉴方案

# 我们的参数装饰器设计
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接口版本控制

# Freqtrade的接口版本
class IStrategy:
    INTERFACE_VERSION = 3  # 当前版本
    
    # 不同版本的参数命名不同
    # v2: buy, sell
    # v3: enter_long, exit_long

借鉴方案

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优势 + 我们的模块化设计

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 配置驱动融合

# 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)