From de5893de3bee78879222d0e7d44a475c079fc842 Mon Sep 17 00:00:00 2001 From: gavindiaz Date: Tue, 7 Jul 2026 20:25:32 +0000 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E8=AF=A6=E7=BB=86=E8=AF=B4?= =?UTF-8?q?=E6=98=8E=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- QSForex详细说明文档.md | 763 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 763 insertions(+) create mode 100644 QSForex详细说明文档.md diff --git a/QSForex详细说明文档.md b/QSForex详细说明文档.md new file mode 100644 index 0000000..2b47131 --- /dev/null +++ b/QSForex详细说明文档.md @@ -0,0 +1,763 @@ +# QSForex 详细说明文档 + +--- + +## 一、项目简介 + +**QSForex** 是一个开源的、基于事件驱动架构的外汇(Forex)量化交易系统,支持**回测**和**实盘交易**。项目由 QuantStart.com 创始人 Michael Halls-Moore 于 2015 年开发,采用 MIT 开源许可证,目前处于 "alpha" 阶段。 + +### 核心特性 + +| 特性 | 说明 | +|------|------| +| 事件驱动架构 | 回测与实盘使用同一套事件接口,策略无需修改即可从回测切换到实盘 | +| Tick 级精度 | 支持逐 tick 级别的多日、多货币对回测 | +| 交易成本 | 回测中默认包含点差(Spread)成本 | +| 多货币对 | 支持同时交易多个货币对 | +| 实盘交易 | 通过 OANDA Brokerage API 进行实盘交易 | +| 绩效分析 | 支持权益曲线、收益率、最大回撤等指标计算与可视化 | +| 单元测试 | 核心计算逻辑有完整的单元测试覆盖 | + +--- + +## 二、项目目录结构 + +``` +qsforex/ +├── __init__.py # 顶层包入口 +├── settings.py # 全局配置(OANDA 凭证、数据路径、杠杆等) +├── logging.conf # 日志配置 +├── requirements.txt # Python 依赖包列表 +│ +├── event/ # ====== 事件系统(核心通信机制) ====== +│ ├── __init__.py +│ └── event.py # 定义 TickEvent / SignalEvent / OrderEvent +│ +├── data/ # ====== 数据层 ====== +│ ├── __init__.py +│ ├── price.py # 历史 CSV 数据读取器(回测用) +│ └── streaming.py # OANDA Streaming API 实时数据流(实盘用) +│ +├── strategy/ # ====== 策略层 ====== +│ ├── __init__.py +│ └── strategy.py # TestStrategy + MovingAverageCrossStrategy +│ +├── portfolio/ # ====== 组合与仓位管理 ====== +│ ├── __init__.py +│ ├── portfolio.py # 资金管理、风险控制、信号执行 +│ ├── position.py # 单个仓位的 P&L 计算 +│ ├── portfolio_test.py # 组合模块单元测试 +│ └── position_test.py # 仓位模块单元测试 +│ +├── execution/ # ====== 执行层 ====== +│ ├── __init__.py +│ └── execution.py # SimulatedExecution + OANDAExecutionHandler +│ +├── backtest/ # ====== 回测引擎 ====== +│ ├── __init__.py +│ ├── backtest.py # Backtest 主循环 +│ └── output.py # 可视化输出(权益曲线、回撤图) +│ +├── performance/ # ====== 绩效计算 ====== +│ ├── __init__.py +│ └── performance.py # 最大回撤(MDD)计算 +│ +├── trading/ # ====== 实盘交易 ====== +│ ├── __init__.py +│ └── trading.py # 多线程实时交易循环 +│ +├── examples/ # ====== 示例 ====== +│ ├── __init__.py +│ └── mac.py # 移动平均线交叉策略回测示例 +│ +└── scripts/ # ====== 辅助脚本 ====== + ├── generate_simulated_pair.py # 生成模拟外汇 tick 数据 + └── test_performance.py # 绩效计算调试脚本 +``` + +--- + +## 三、事件驱动架构详解 + +### 3.1 概述 + +整个系统围绕一个**事件队列(Event Queue)** 运转。事件是系统中各组件之间通信的唯一方式。这种设计使得各模块高度解耦,策略代码在回测和实盘之间无需修改即可复用。 + +### 3.2 事件类型 + +系统定义了三种事件,按处理顺序依次流转: + +``` +数据源 → TickEvent → 策略 → SignalEvent → 组合 → OrderEvent → 执行引擎 +``` + +#### TickEvent(行情事件) + +由数据层产生,包含市场报价信息。 + +```python +class TickEvent(Event): + def __init__(self, instrument, time, bid, ask): + self.type = 'TICK' + self.instrument = instrument # 货币对,如 "GBPUSD" + self.time = time # 时间戳 + self.bid = bid # 买价 + self.ask = ask # 卖价 +``` + +#### SignalEvent(信号事件) + +由策略层产生,表示一个交易决策。 + +```python +class SignalEvent(Event): + def __init__(self, instrument, order_type, side, time): + self.type = 'SIGNAL' + self.instrument = instrument # 货币对 + self.order_type = order_type # 订单类型(当前仅支持 "market") + self.side = side # 方向:"buy" 或 "sell" + self.time = time # 产生信号的 tick 时间 +``` + +#### OrderEvent(订单事件) + +由组合层产生,表示一个需要发送到经纪商的实际订单。 + +```python +class OrderEvent(Event): + def __init__(self, instrument, units, order_type, side): + self.type = 'ORDER' + self.instrument = instrument # 货币对 + self.units = units # 交易数量 + self.order_type = order_type # 订单类型 + self.side = side # 方向 +``` + +### 3.3 事件流向图 + +``` + ┌──────────────┐ + │ 数据源 │ + │ (CSV/OANDA) │ + └──────┬───────┘ + │ TickEvent + ▼ + ┌───────────────────────┐ + │ 事件队列 (Queue) │ + └───────┬───────────────┘ + │ + ┌──────────────┼──────────────┐ + ▼ ▼ ▼ + ┌──────────┐ ┌──────────┐ ┌──────────┐ + │ 策略 │ │ 组合 │ │ 执行 │ + │ (Strategy)│ │(Portfolio)│ │(Execution)│ + └─────┬────┘ └─────┬────┘ └──────────┘ + │ │ + │ SignalEvent │ OrderEvent + └─────────────┘ + (放回事件队列) +``` + +--- + +## 四、各模块详细说明 + +### 4.1 数据层(data/) + +#### 4.1.1 PriceHandler(抽象基类) + +[price.py](file:///c:/Users/Administrator/Desktop/qsforex/data/price.py#L15-L76) + +所有数据处理器继承自 `PriceHandler`,提供以下核心功能: + +- **`_set_up_prices_dict()`**:构建价格字典,同时维护正向和反向汇率对。例如,当交易 `GBPUSD` 时,系统自动计算并维护 `USDGBP` 的 bid/ask,用于跨货币对的盈亏换算。 +- **`invert_prices()`**:将 bid/ask 价格取倒数,生成反向汇率对。 + +#### 4.1.2 HistoricCSVPriceHandler(历史数据处理器) + +[price.py](file:///c:/Users/Administrator/Desktop/qsforex/data/price.py#L77-L202) + +用于回测场景,从 CSV 文件读取历史 tick 数据。 + +**数据格式**:兼容 DukasCopy Historical Data Feed 格式,文件名格式为 `{货币对}_{YYYYMMDD}.csv`,例如 `GBPUSD_20140112.csv`。 + +CSV 文件内部格式: +``` +Time,Ask,Bid,AskVolume,BidVolume +12.01.2014 22:00:10.123,1.50200,1.50180,1.50,1.50 +``` + +**处理流程**: +1. 扫描 `CSV_DATA_DIR` 目录下所有符合格式的 CSV 文件 +2. 提取所有日期,去重排序 +3. 按天加载数据,使用 Pandas 将多个货币对的数据按时间合并排序 +4. `stream_next_tick()` 方法每次被调用时,按时间顺序输出下一个 tick +5. 每输出一个 tick,同时更新正向和反向汇率对的价格 + +#### 4.1.3 StreamingForexPrices(实时数据流处理器) + +[streaming.py](file:///c:/Users/Administrator/Desktop/qsforex/data/streaming.py#L16-L91) + +用于实盘交易场景,通过 OANDA 的 Streaming API 获取实时价格。 + +**处理流程**: +1. 建立到 OANDA streaming 端点的 HTTPS 连接 +2. 使用 `requests.Session` 的流式传输持续接收数据 +3. 逐行解析 JSON 格式的 tick 数据 +4. 生成 `TickEvent` 放入事件队列 +5. 同步更新正向和反向汇率对价格 + +--- + +### 4.2 策略层(strategy/) + +[strategy.py](file:///c:/Users/Administrator/Desktop/qsforex/strategy/strategy.py) + +策略层负责从 `TickEvent` 中分析市场数据,产生交易信号。所有策略必须实现 `calculate_signals(event)` 方法。 + +#### 4.2.1 TestStrategy(测试策略) + +简单的测试策略,每 5 个 tick 交替买入/卖出。设计目的是持续"穿越点差",因此必然亏损,仅用于验证系统运行是否正常。 + +``` +逻辑: + tick 0-4: 无操作 + tick 5: BUY → 持仓 + tick 10: SELL → 平仓 + tick 15: BUY → 持仓 + ...循环 +``` + +#### 4.2.2 MovingAverageCrossStrategy(双均线交叉策略) + +经典的移动平均线交叉策略,仅做多。 + +**参数**: +| 参数 | 默认值 | 说明 | +|------|--------|------| +| `short_window` | 500 | 短期 SMA 窗口(tick 数) | +| `long_window` | 2000 | 长期 SMA 窗口(tick 数) | + +**信号逻辑**: +- 短期 SMA 上穿长期 SMA 且未持仓 → 产生 `BUY` 信号(开多仓) +- 短期 SMA 下穿长期 SMA 且已持仓 → 产生 `SELL` 信号(平多仓) + +**性能优化**:使用**滚动 SMA 算法**,避免每次重新计算完整均线: +```python +def calc_rolling_sma(self, sma_m_1, window, price): + return ((sma_m_1 * (window - 1)) + price) / window +``` +该算法将时间复杂度从 O(n) 降为 O(1)。 + +**多货币对支持**:通过 `pairs_dict` 为每个货币对维护独立的 tick 计数、持仓状态和 SMA 值。 + +--- + +### 4.3 组合与仓位管理(portfolio/) + +#### 4.3.1 Position(仓位类) + +[position.py](file:///c:/Users/Administrator/Desktop/qsforex/portfolio/position.py#L5-L108) + +管理单个货币对的交易仓位,支持多空双向。 + +**核心属性**: +| 属性 | 说明 | +|------|------| +| `home_currency` | 账户计价货币(如 GBP) | +| `position_type` | 仓位方向:`"long"` 或 `"short"` | +| `currency_pair` | 交易货币对(如 EURUSD) | +| `units` | 持仓数量 | +| `avg_price` | 平均持仓成本 | +| `cur_price` | 当前市场价格 | +| `profit_base` | 以计价货币计算的浮动盈亏 | +| `profit_perc` | 浮动盈亏百分比 | + +**关键方法**: +| 方法 | 说明 | +|------|------| +| `calculate_pips()` | 计算当前盈亏点数 | +| `calculate_profit_base()` | 计算以账户货币计价的盈亏金额 | +| `update_position_price()` | 更新当前价格并重新计算盈亏 | +| `add_units(units)` | 加仓,重新计算平均成本 | +| `remove_units(units)` | 减仓,返回已实现盈亏 | +| `close_position()` | 平仓,返回已实现盈亏 | + +**跨货币对换算**:对于 EUR/USD 仓位,账户以 GBP 计价时的盈亏计算: +``` +Profit_GBP = Pips × USD/GBP_Rate × Units +``` + +#### 4.3.2 Portfolio(组合类) + +[portfolio.py](file:///c:/Users/Administrator/Desktop/qsforex/portfolio/portfolio.py#L20-L193) + +管理整个交易组合,负责资金管理、风险控制和信号执行。 + +**核心属性**: +| 属性 | 默认值 | 说明 | +|------|--------|------| +| `equity` | 100,000.00 | 账户总权益 | +| `balance` | = equity | 当前余额 | +| `leverage` | 20 | 杠杆倍数 | +| `risk_per_trade` | 0.02 (2%) | 单笔交易风险比例 | +| `trade_units` | equity × 0.02 | 单笔交易头寸规模 | + +**关键方法**: +| 方法 | 说明 | +|------|------| +| `calc_risk_position_size()` | 计算基于风险的仓位大小 | +| `add_new_position()` | 创建新仓位 | +| `add_position_units()` | 对已有仓位加仓 | +| `remove_position_units()` | 对已有仓位减仓 | +| `close_position()` | 平掉整个仓位 | +| `update_portfolio(tick_event)` | 更新所有持仓的浮动盈亏 | +| `execute_signal(signal_event)` | 执行交易信号,生成 OrderEvent | +| `output_results()` | 输出回测结果到 CSV | +| `create_equity_file()` | 创建回测结果 CSV 文件 | + +**信号执行逻辑** [execute_signal](file:///c:/Users/Administrator/Desktop/qsforex/portfolio/portfolio.py#L135-L192): + +| 信号方向 | 当前仓位 | 动作 | +|---------|---------|------| +| `buy` | 无仓位 | 创建多头仓位 | +| `buy` | 有多头仓位 | 加仓 | +| `buy` | 有空头仓位 | 若 units 相等则平仓 | +| `sell` | 无仓位 | 创建空头仓位 | +| `sell` | 有多头仓位 | 若 units 相等则平仓 | +| `sell` | 有空头仓位 | 加仓 | + +--- + +### 4.4 执行层(execution/) + +[execution.py](file:///c:/Users/Administrator/Desktop/qsforex/execution/execution.py) + +#### 4.4.1 ExecutionHandler(抽象基类) + +定义了 `execute_order()` 接口,所有执行处理器必须实现此方法。 + +#### 4.4.2 SimulatedExecution(模拟执行) + +回测模式下的执行器,`execute_order()` 方法为空操作。实际的成交处理由 `Portfolio` 对象直接完成。 + +#### 4.4.3 OANDAExecutionHandler(OANDA 执行器) + +实盘模式下的执行器,通过 OANDA REST API 发送订单。 + +**下单流程**: +1. 建立到 OANDA API 域名的 HTTPS 连接 +2. 构造 HTTP POST 请求,包含认证信息和订单参数 +3. 发送到 `/v1/accounts/{account_id}/orders` 端点 +4. 记录 API 响应日志 + +--- + +### 4.5 回测引擎(backtest/) + +#### 4.5.1 Backtest 类 + +[backtest.py](file:///c:/Users/Administrator/Desktop/qsforex/backtest/backtest.py#L12-L82) + +回测引擎的核心类,将所有组件组装在一起运行回测。 + +**初始化参数**: +| 参数 | 说明 | +|------|------| +| `pairs` | 交易货币对列表 | +| `data_handler` | 数据处理器类(如 `HistoricCSVPriceHandler`) | +| `strategy` | 策略类(如 `MovingAverageCrossStrategy`) | +| `strategy_params` | 策略参数字典 | +| `portfolio` | 组合管理类 | +| `execution` | 执行处理器类 | +| `equity` | 初始资金 | +| `heartbeat` | 事件循环心跳间隔(秒) | +| `max_iters` | 最大迭代次数 | + +**回测主循环** `_run_backtest()`: +```python +while iters < max_iters and ticker.continue_backtest: + try: + event = events.get(False) # 非阻塞获取事件 + except queue.Empty: + ticker.stream_next_tick() # 没有事件则推进下一个 tick + else: + if event.type == 'TICK': + strategy.calculate_signals(event) # 策略分析 + portfolio.update_portfolio(event) # 更新盈亏 + elif event.type == 'SIGNAL': + portfolio.execute_signal(event) # 执行信号 + elif event.type == 'ORDER': + execution.execute_order(event) # 执行订单 + time.sleep(heartbeat) + iters += 1 +``` + +**关键设计**:当事件队列为空时,主动从数据源获取下一个 tick 并放入队列,而非等待。这种"拉取"模式确保回测的确定性和可复现性。 + +#### 4.5.2 可视化输出 + +[output.py](file:///c:/Users/Administrator/Desktop/qsforex/backtest/output.py) + +读取 `equity.csv` 文件,使用 Matplotlib + Seaborn 绘制三张图表: + +1. **权益曲线**(上图):组合价值随时间变化 +2. **期间收益率**(中图):每个 tick 的收益率 +3. **回撤曲线**(下图):从历史高点的回撤幅度 + +--- + +### 4.6 绩效计算(performance/) + +[performance.py](file:///c:/Users/Administrator/Desktop/qsforex/performance/performance.py) + +`create_drawdowns(pnl)` 函数: + +- 计算权益曲线的**峰值到谷值的最大回撤(Maximum Drawdown, MDD)** +- 计算**回撤持续时间** +- 返回 `(drawdown_series, max_drawdown, max_duration)` + +--- + +### 4.7 实盘交易(trading/) + +[trading.py](file:///c:/Users/Administrator/Desktop/qsforex/trading/trading.py) + +实盘交易的入口,使用**双线程**架构: + +``` +线程 1(价格流): StreamingForexPrices.stream_to_queue() + └── 持续从 OANDA 接收实时价格,生成 TickEvent 放入队列 + +线程 2(交易循环): trade() + └── 从队列获取事件 → 策略 → 组合 → 执行 +``` + +--- + +## 五、配置文件说明 + +### 5.1 settings.py + +```python +# OANDA 环境配置 +ENVIRONMENTS = { + "streaming": { + "real": "stream-fxtrade.oanda.com", + "practice": "stream-fxpractice.oanda.com", + "sandbox": "stream-sandbox.oanda.com" + }, + "api": { + "real": "api-fxtrade.oanda.com", + "practice": "api-fxpractice.oanda.com", + "sandbox": "api-sandbox.oanda.com" + } +} + +# 数据目录和输出目录(从环境变量读取) +CSV_DATA_DIR = os.environ.get('QSFOREX_CSV_DATA_DIR', None) +OUTPUT_RESULTS_DIR = os.environ.get('QSFOREX_OUTPUT_RESULTS_DIR', None) + +# 交易环境选择 +DOMAIN = "practice" # "practice" / "real" / "sandbox" + +# OANDA 认证 +ACCESS_TOKEN = os.environ.get('OANDA_API_ACCESS_TOKEN', None) +ACCOUNT_ID = os.environ.get('OANDA_API_ACCOUNT_ID', None) + +# 账户设置 +BASE_CURRENCY = "GBP" # 账户基础货币 +EQUITY = Decimal("100000.00") # 初始资金 +``` + +### 5.2 logging.conf + +[logging.conf](file:///c:/Users/Administrator/Desktop/qsforex/logging.conf) + +配置了 root logger 和 `qsforex.trading.trading` logger,均输出到控制台,级别为 DEBUG。 + +--- + +## 六、使用流程 + +### 6.1 回测流程 + +``` +步骤 1: 生成模拟数据 +└── python scripts/generate_simulated_pair.py GBPUSD + +步骤 2: 运行回测 +└── python examples/mac.py + +步骤 3: 查看结果 +└── python backtest/output.py +``` + +### 6.2 实盘交易流程 + +``` +步骤 1: 配置 OANDA 凭证(settings.py) +步骤 2: 编写策略(继承策略基类) +步骤 3: 启动交易 +└── python trading/trading.py +``` + +--- + +## 七、技术栈 + +| 类别 | 依赖包 | 版本 | +|------|--------|------| +| 数值计算 | numpy | 1.9.2 | +| 科学计算 | scipy | 0.15.1 | +| 数据处理 | pandas | 0.16.1 | +| 可视化 | matplotlib | 1.4.3 | +| 统计可视化 | seaborn | 0.5.1 | +| 机器学习 | scikit-learn | 0.16.1 | +| HTTP 请求 | requests | 2.7.0 | +| 测试框架 | nose | 1.3.6 | +| Mock | mock | 1.0.1 | +| 交互环境 | ipython | 3.1.0 | + +--- + +## 八、已知问题与改进建议 + +### 8.1 兼容性问题 + +| 问题 | 严重程度 | 说明 | +|------|---------|------| +| Python 2.7 语法 | 高 | 使用 `from __future__`、`try: import Queue`、`__metaclass__` 等旧式写法,无法在 Python 3 上直接运行 | +| 依赖版本过旧 | 高 | pandas 0.16、numpy 1.9 发布于 2015 年,存在安全漏洞 | +| OANDA API 版本 | 高 | 使用 OANDA v1 API,该版本已被废弃,需迁移到 v3 REST API | + +### 8.2 代码缺陷 + +| 问题 | 位置 | 说明 | +|------|------|------| +| 缺少 `self.` 前缀 | [portfolio.py L165](file:///c:/Users/Administrator/Desktop/qsforex/portfolio/portfolio.py#L165) | `add_position_units` 应为 `self.add_position_units`,会导致 `NameError` | +| 无 setup.py | 根目录 | 缺少标准的 Python 包安装配置,无法通过 `pip install` 安装 | +| 硬编码 | [generate_simulated_pair.py](file:///c:/Users/Administrator/Desktop/qsforex/scripts/generate_simulated_pair.py) | 模拟数据生成的日期、初始价格等参数硬编码 | + +### 8.3 改进建议 + +1. **Python 3 迁移**:将所有语法升级到 Python 3.6+,移除 `from __future__` 导入 +2. **依赖更新**:升级到最新版本的 pandas、numpy 等核心依赖 +3. **API 升级**:将 OANDA API 从 v1 迁移到 v3 +4. **包管理现代化**:添加 `setup.py` 或 `pyproject.toml` +5. **Bug 修复**:修复 portfolio.py 中缺失 `self.` 的问题 +6. **配置外部化**:将模拟数据生成参数从硬编码改为配置文件或命令行参数 + +--- + +## 九、扩展指南 + +### 9.1 编写自定义策略 + +只需继承或模仿现有策略,实现 `calculate_signals(event)` 方法: + +```python +class MyCustomStrategy(object): + def __init__(self, pairs, events): + self.pairs = pairs + self.events = events + # 初始化你的策略状态 + + def calculate_signals(self, event): + if event.type == 'TICK': + # 你的策略逻辑 + # 当满足条件时,生成 SignalEvent + signal = SignalEvent(pair, "market", "buy", event.time) + self.events.put(signal) +``` + +然后在回测或实盘入口中替换策略类即可。 + +### 9.2 添加新的数据源 + +继承 `PriceHandler` 基类,实现数据获取和 `stream_next_tick()` 方法。 + +--- + +## 十、许可证 + +MIT License - Copyright (c) 2015 Michael Halls-Moore + +--- + +> **风险提示**:外汇保证金交易具有高风险,可能不适合所有投资者。过去的表现不代表未来的结果。高杠杆可能对您不利也可能对您有利。在决定投资外汇之前,您应仔细考虑您的投资目标、经验水平和风险承受能力。 + +--- + +## 十一、可复用模块分析 —— 多项目整合视角 + +> 本章节专门为**综合多个项目构建自有交易系统**的开发者编写,帮助你快速识别 QSForex 中最值得借鉴和复用的模块,以及它在多项目组合中的定位。 + +### 11.1 本项目在量化交易系统中的定位 + +QSForex 的核心价值在于**轻量级、教学友好、架构清晰**。它不是一个功能完备的生产级系统,而是一个**架构原型**——用最少的代码完整展示了事件驱动交易系统的骨架。在多项目整合中,QSForex 适合作为: + +| 角色 | 说明 | +|------|------| +| **架构参考蓝图** | 事件驱动模式是量化交易系统的主流范式,本项目的实现简洁易懂 | +| **快速原型验证** | 当你有一个新策略想法时,可以最快速度搭出回测环境 | +| **教学/入门材料** | 代码量小、注释清晰,适合团队新成员快速理解量化系统全貌 | + +--- + +### 11.2 模块可复用性矩阵 + +以下按照**可复用价值从高到低**排列,并标注每个模块在多项目整合中的建议处理方式。 + +#### ⭐⭐⭐⭐⭐ 强烈推荐复用/借鉴 + +| 模块 | 核心价值 | 可复用部分 | 跨市场适用性 | +|------|---------|-----------|-------------| +| **事件驱动架构** | ⭐⭐⭐⭐⭐ | 整个事件队列 + 事件类型设计 | 股票/期货/加密货币均可 | +| **回测引擎** | ⭐⭐⭐⭐⭐ | `Backtest._run_backtest()` 主循环 | 通用,只需替换数据源 | +| **仓位管理** | ⭐⭐⭐⭐⭐ | `Position` 类的盈亏计算逻辑 | 外汇特有,但多空双向模式通用 | +| **滚动 SMA 算法** | ⭐⭐⭐⭐ | `calc_rolling_sma()` 高效增量计算 | 所有时间序列策略通用 | + +#### 详细分析 + +**① 事件驱动架构(最核心的复用价值)** + +``` +事件类型设计 → 事件队列 → 事件分发循环 +``` + +这是 QSForex 的灵魂。无论你最终使用什么市场、什么语言、什么数据库,这个**三层解耦**的模式是量化交易系统的事实标准: + +``` +数据层 ──TickEvent──→ 策略层 ──SignalEvent──→ 组合层 ──OrderEvent──→ 执行层 + ↑ ↑ ↑ ↑ + 可替换 可替换 可替换 可替换 +``` + +**迁移建议**: +- 保留事件类型定义(TickEvent / SignalEvent / OrderEvent),按需扩展(如增加 `FillEvent`、`RiskEvent`) +- 保留事件队列 + `while` 循环分发的模式 +- 替换各层具体实现即可适配任何市场 + +**② 回测引擎主循环** + +[backtest.py](file:///c:/Users/Administrator/Desktop/qsforex/backtest/backtest.py#L41-L64) 中的 `_run_backtest()` 方法是经典的回测主循环模式: + +```python +while iters < max_iters and ticker.continue_backtest: + try: + event = events.get(False) # 非阻塞取事件 + except queue.Empty: + ticker.stream_next_tick() # 无事件时推进数据 + else: + if event.type == 'TICK': + strategy.calculate_signals(event) + portfolio.update_portfolio(event) + elif event.type == 'SIGNAL': + portfolio.execute_signal(event) + elif event.type == 'ORDER': + execution.execute_order(event) +``` + +**迁移建议**: +- 这个循环结构可以直接移植到任何市场(股票、期货、加密货币) +- 只需实现对应市场的 `PriceHandler` 子类即可 +- 可以扩展为支持 `BarEvent`(K线事件)以适配日线级别策略 + +**③ 仓位盈亏计算** + +[position.py](file:///c:/Users/Administrator/Desktop/qsforex/portfolio/position.py) 中的 `Position` 类实现了完整的: +- 多空双向持仓 +- 平均成本计算(加仓/减仓时重新计算) +- 已实现/未实现盈亏分离 +- 跨货币换算 + +**迁移建议**: +- 外汇特有的汇率换算部分可以剥离,核心的 `avg_price` 加权平均算法是通用的 +- 期货/股票场景下,需增加保证金计算、合约乘数等字段 +- 加密货币场景几乎可以直接复用 + +**④ 滚动 SMA 增量算法** + +[strategy.py](file:///c:/Users/Administrator/Desktop/qsforex/strategy/strategy.py#L69-L70) 中的高效均线计算: + +```python +def calc_rolling_sma(self, sma_m_1, window, price): + return ((sma_m_1 * (window - 1)) + price) / window +``` + +这个算法将 SMA 计算从 O(n) 优化到 O(1),在高频回测中效果显著。 + +--- + +#### ⭐⭐⭐ 可借鉴思路,需重新实现 + +| 模块 | 核心价值 | 需改造的原因 | +|------|---------|-------------| +| **数据层** | CSV 多文件按天加载、多货币对按时间归并 | 格式绑定 DukasCopy,且 Python 2.7 的 pandas 语法已过时 | +| **信号执行逻辑** | buy/sell 与多空仓位的状态机 | 逻辑有 Bug(缺少 `self.`),且不支持部分平仓 | +| **绩效计算** | 最大回撤计算 | 实现过于简单,现代系统需要 Sharpe/Sortino/Calmar 等 | +| **可视化输出** | 三图布局(权益+收益+回撤) | matplotlib 版本过旧,可用 plotly/bokeh 替换 | + +--- + +#### ⭐⭐ 参考价值有限,建议替换 + +| 模块 | 原因 | +|------|------| +| **OANDA 执行器** | 使用已废弃的 OANDA v1 API,必须用 v3 重写或换经纪商 | +| **实时数据流** | 同上,API 版本过时 | +| **模拟数据生成** | 仅生成随机游走数据,无市场微观结构,建议用专业回测数据源 | +| **日志配置** | 可用 structlog 或 loguru 替代 | + +--- + +### 11.3 多项目整合的推荐架构 + +如果你正在综合多个项目构建自己的交易系统,推荐的分层架构如下: + +``` +┌─────────────────────────────────────────────────────┐ +│ 策略层 (Strategy) │ +│ 从 QSForex 借鉴:事件接口 + calculate_signals │ +│ 从其他项目借鉴:因子计算、ML模型、信号组合 │ +├─────────────────────────────────────────────────────┤ +│ 组合层 (Portfolio) │ +│ 从 QSForex 借鉴:多空仓位管理 + 风险头寸计算 │ +│ 从其他项目借鉴:凯利公式、VaR、组合优化 │ +├─────────────────────────────────────────────────────┤ +│ 执行层 (Execution) │ +│ 从 QSForex 借鉴:SimulatedExecution(回测模式) │ +│ 从其他项目借鉴:多经纪商适配、订单路由、智能下单 │ +├─────────────────────────────────────────────────────┤ +│ 数据层 (Data) │ +│ 从 QSForex 借鉴:多标的按时间归并的思想 │ +│ 从其他项目借鉴:实时数据库、数据清洗、复权处理 │ +├─────────────────────────────────────────────────────┤ +│ 事件总线 (Event Bus) │ +│ 从 QSForex 借鉴:Events Queue + 事件类型体系 ★★★ │ +│ 从其他项目借鉴:Redis/Kafka 分布式事件总线 │ +└─────────────────────────────────────────────────────┘ +``` + +--- + +### 11.4 QSForex 在多项目组合中的角色总结 + +| 维度 | QSForex 的定位 | +|------|---------------| +| **架构教学** | 🥇 最佳入门教材——事件驱动模式的最简实现 | +| **回测引擎** | 🥈 可作为快速原型验证工具 | +| **策略开发** | 🥈 内置策略简单,但策略接口设计值得参考 | +| **生产就绪度** | ❌ 不适合直接用于生产环境 | +| **跨市场支持** | ❌ 仅外汇,需大量改造才能支持股票/期货 | +| **代码质量** | ⚠️ 有已知 Bug,需要修复后再复用 | + +**推荐的复用策略**: + +1. **提取事件驱动骨架**:将 `event/` + `backtest/` 的核心循环提取为通用框架 +2. **修复并提取仓位管理**:修复 `portfolio.py` 的 Bug,抽象出通用的 `Position` 基类 +3. **保留策略接口规范**:统一 `calculate_signals(event)` 签名作为所有策略的入口规范 +4. **替换其他所有模块**:数据源、执行器、绩效分析、可视化全部用现代方案重新实现 + +> **一句话总结**:QSForex 的**事件驱动架构 + 回测主循环 + 仓位管理**是最值得带走的核心资产,其余模块建议用其他项目的更成熟实现替代。 \ No newline at end of file