小果海龟交易策略回测系统专家
一、系统概述
使用教程:https://gitcode.com/qq_50882340/xg_hg_backtrader
1.1 系统定位
小果海龟交易策略回测系统(xg_hg_backtrader)是一套忠实还原经典海龟交易法则(Turtle Trading Rules)并叠加做T增厚收益的专业级量化回测框架。它以「唐奇安通道(Donchian Channel)突破」为入市/离市信号,以「N 值(平均真实波幅的指数平滑)」度量市场波动风险,按「每笔固定风险比例」动态计算每次交易的头寸单位大小,并在趋势中「逐 N 值金字塔加仓」,配合「2N 波动止损」控制单笔亏损,最后叠加「当日大涨止盈卖出 / 当日大跌止损买入」的做T规则在盘中降低成本。它按每只标的独立资金池逐日撮合,输出完整绩效。
与其它策略系统最大的不同在于:海龟系统不预测方向、不做横盘收割,而是严格追踪趋势——只在价格向上突破 entry_period 日最高点时顺势做多,趋势衰竭(跌破 exit_period 日低点)后离场;风险完全由「N 值 × 风险参数」这一波动刻度来控制,从而把「该买多少」与「该在哪止损」全部换算成波动单位,实现风险平价。
经典海龟法则核心:波动 1%(N)的价格变动 = 1 单位风险的等价波动。海龟并不预测价格会走多远,而是保证「任何一笔亏损都不超过账户固定比例」,让趋势来界定盈亏。
1.2 核心策略逻辑(每个交易日逐标的执行)
海龟框架在每个标的、每个交易日按以下顺序执行一套完整的「离市 → 止损 → 入市 → 加仓 → 记账」流水线:
每日逐标的决策顺序:
① 做T(若有持仓且当日涨跌幅达标)
├─ 当日 zdf ≥ sell_zdf → 做T止盈卖出(trade_value 金额,≤持仓市值30%)
└─ 当日 zdf ≤ buy_zdf → 做T止损买入(trade_value 金额,≤可用现金30%)
② 海龟离市(exit_signal==1,跌破 exit_period 日低点)→ 平多仓
③ 海龟止损(跌破 入市价 − 2×N)→ 全仓止损离场
④ 海龟入市(无持仓且 entry_signal==1,突破 entry_period 日高点)→ 开多仓 1 单位
⑤ 海龟加仓(有持仓且价 ≥ 入市价 + N×add_unit_threshold,且 current_units < max_units)→ 加仓 1 单位
⑥ 记账:更新总资产/持仓/成本/当日盈亏/累计盈亏/收益率
每个交易日只能开一次仓、加一次仓(以突破发生为准),但同一天可叠加做T、止损等动作;动作以 ; 拼接记录在当日 action 中。
1.3 海龟策略信号引擎(关键概念)
海龟系统的一切都围绕「波动刻度 N」与「唐奇安通道」两个核心:
| 概念 | 公式 | 说明 |
| :--- | :--- | :--- |
| 真实波幅 TR | max(high−low, \|high−前收\|, \|low−前收\|) | 单日真实波动 |
| N 值 | TR 的 n_period 期 EWM(span=N,adjust=False) | 平滑后的平均波动,作为风险刻度 |
| 入市通道上轨 | 前 entry_period 日 high 的最大值(shift 1) | 向上突破 → 开多仓 |
| 入市通道下轨 | 前 entry_period 日 low 的最小值(shift 1) | 向下突破 → 开空(本系统 use_long_system=False 仅做多) |
| 离市通道下轨 | 前 exit_period 日 low 的最小值(shift 1) | 向下突破 → 平多仓离场 |
| 单位大小 | (每标资金 × risk_per_trade) ÷ (N × risk_per_unit) | 波动等风险头寸,clip 到 [min_shares, 半仓] |
| 加仓触发价 | 入市价 + N × add_unit_threshold | 价格每再涨 add_unit_threshold 个 N,加 1 单位 |
| 止损价 | 入市价 − 2 × N | 跌破即全仓止损(2N 波动止损) |
⚠️ 所有通道均使用
shift(1),即用昨日及之前的数据确认突破,天然无未来函数。
1.4 经典海龟法则 → 本框架参数映射
| 经典海龟法则(原版) | 本框架参数 | 默认 | 说明 |
| :--- | :--- | :--- | :--- |
| 系统1:20日突破入市 / 10日突破离市 | entry_period / exit_period | 20 / 10 | 唐奇安通道周期 |
| N = 20日ATR的指数平均 | n_period | 20 | N 值平滑周期(EWM span) |
| 每笔风险 ≤ 账户 1% | risk_per_trade | 0.01 | 单笔最大风险占每标资金比例 |
| 每 N(1%波动)风险 2% 本金 | risk_per_unit | 0.02 | 单位资金波动对应的风险 |
| 单标的限 4 单位(金字塔式) | max_units | 4 | 最大同时持有单位数 |
| 每涨 0.5N 加 1 单位 | add_unit_threshold | 0.5 | 加仓所需 N 值倍数 |
| 2N 波动止损 | (固定 2×N) | 2 | 代码固定为 2 倍 N |
| 盈利单可移止损至 2N | (未启用) | — | 本版未实现移动止损 |
1.5 设计哲学
- 解耦与复用:信号计算(
calculate_turtle_signals)、资金管理、交易撮合、绩效评估各环节解耦,每个模块可独立优化。 - 透明与可解释:每个交易日记录 N 值、持仓单位数、入市价、加仓价,动作全程可追溯,决策完全透明。
- 风险优先:以波动(N)而非价格点数作为风险与止损刻度,天然适应不同波动率的标的,实现风险平价。
- 灵活与扩展:支持自定义数据注入(标的+指数各 7 种接口)、多标的多资金池、做T 独立开关,可继承重写核心方法做二次开发。
二、安装与运行环境
2.1 安装包
小果海龟交易策略回测系统以单个类文件 xg_hg_backtrader.py 形式提供,无独立安装步骤。将脚本置于工作目录后,在同一目录(或旁路)下放置数据文件即可使用。
使用教程:https://gitcode.com/qq_50882340/xg_hg_backtrader
2.2 依赖
Python ≥ 3.8- 第三方库:
pandas、numpy - 本地数据源可选依赖:
pyarrow(读取.parquet历史数据) - 无需安装
xg_tdx_func(本框架不涉及通达信公式引擎)
安装依赖:
pip install pandas numpy pyarrow
2.3 包结构
工作目录/
├── xg_hg_backtrader.py # 主类文件(class xg_hg_backtrader)
├── data/
│ ├── 历史数据/ # 本地标的日线 parquet(代码.parquet)
│ └── (可选) 指数历史文件 # 指数数据(未注入自定义指数时)
└── 策略模型/
└── 海龟策略/<user>/ # save_backtrader_data 导出目录(自动创建)
2.4 导入方式
from xg_hg_backtrader.xg_hg_backtrader import xg_hg_backtrader
bt = xg_hg_backtrader(
start_date='20230101',
end_date='20261201',
stock_list=['513100.SH', '513500.SH'],
cash=1000000,
)
2.5 数据目录要求(使用内置数据源时)
当未注入自定义数据(use_custom_data=False)时,系统会按以下路径依次查找单只标的的日线 parquet:
data/历史数据/{stock_code}.parquet
data/stock_data/{stock_code}.parquet
data/{stock_code}.parquet
上级目录/data/历史数据/{stock_code}.parquet
找到即用;找不到该标的则跳过并在控制台报「数据不足」。
2.6 数据字段要求
标的(股票/ETF)日线数据需包含以下字段:
| 字段 | 说明 | 是否必须 |
| :--- | :--- | :--- |
| date | 交易日期 | ✅ 必须 |
| close | 收盘价 | ✅ 必须(>0) |
| open | 开盘价 | ✅ 必须(>0) |
| high | 最高价 | ✅ 必须(缺省自动=close) |
| low | 最低价 | ✅ 必须(缺省自动=close) |
| volume | 成交量 | ✅ 必须 |
| zdf | 涨跌幅 | ⚠️ 推荐(缺失自动计算) |
| preClose | 前收盘价 | ⚠️ 推荐(用于复权因子计算) |
| amount | 成交金额 | ⚠️ 可选 |
| 证券代码 | 股票代码 | ⚠️ 可选(自动补) |
海龟信号依赖
high/low计算 TR 与唐奇安通道,因此数据行数需 ≥ max(entry, exit, n)+10,否则该标的信号全为 0 被跳过;_load_single_stock还要求数据 >50 行才接受。
指数数据仅需 date + close(close>0)。
三、初始化参数完整参考
以下为
__init__方法全部参数的详细说明,按功能分组。
3.1 基础参数 (Base)
| 参数 | 类型 | 默认值 | 说明 |
| :--- | :--- | :--- | :--- |
| start_date | str | '20240101' | 回测起始日期,格式 YYYYMMDD |
| end_date | str | '20500101' | 回测结束日期,格式同上 |
| stock_list | list | ['513100.SH','513500.SH'] | 候选标的池,元素需带交易所后缀 |
| index_stock | str | '000300.SH' | 基准指数代码(用于输出参考) |
| cash | float | 100000 | 初始总资金(元),会均分到每只标的 |
| comm | float | 0.0001 | 手续费率(万1 = 0.0001) |
| max_workers | int | 4 | 数据加载并发线程数 |
3.2 海龟策略参数 (Turtle)
| 参数 | 类型 | 默认值 | 说明 |
| :--- | :--- | :--- | :--- |
| entry_period | int | 20 | 入市唐奇安通道周期(突破 N 日高点开多) |
| exit_period | int | 10 | 离市唐奇安通道周期(跌破 N 日低点平多) |
| n_period | int | 20 | N 值(ATR)EWM 平滑周期 |
| risk_per_trade | float | 0.01 | 每笔风险占每标资金比例(经典 1%) |
| risk_per_unit | float | 0.02 | 单位资金波动风险(经典 2% 本金) |
| max_units | int | 4 | 单标的最高持仓单位数(金字塔上限) |
| add_unit_threshold | float | 0.5 | 加仓所需 N 值倍数(每涨 0.5N 加一单位) |
3.3 做T参数 (Day-Trade / DT)
| 参数 | 类型 | 默认值 | 说明 |
| :--- | :--- | :--- | :--- |
| sell_zdf | float | 0.03 | 当日涨幅达此值触发做T止盈卖出 |
| buy_zdf | float | -0.03 | 当日跌幅达此值触发做T止损买入 |
| trade_value | float | 1000 | 每次做T的下单金额(元) |
3.4 数据源开关 (Data Source)
| 参数 | 类型 | 默认值 | 说明 |
| :--- | :--- | :--- | :--- |
| use_custom_data | bool | False | 是否使用注入的自定义标的数据库(自动切换) |
| use_custom_index_data | bool | False | 是否使用注入的自定义指数数据(自动切换) |
3.5 内部固定参数(构造时自动设置,一般不修改)
| 参数 | 默认值 | 说明 |
| :--- | :--- | :--- |
| verbose | True | 是否打印回测过程日志 |
| adj_type | 'none' | 复权类型(当前固定 none,需复权可在 _normalize_dataframe 扩展) |
| min_shares | 100 | 单笔最小成交股数(1 手) |
| share_multiple | 100 | 成交股数整数倍(按 100 手撮合) |
| use_long_system | False | 是否启用做空系统(本版固定 False,仅做多) |
| enable_dt | True | 是否启用做T(可手动设为 False 关闭) |
| debug | False | 调试开关 |
3.6 关键口径:每标资金池与单位资金
| 概念 | 公式 | 说明 |
| :--- | :--- | :--- |
| 每标资金池 per_stock_cash | cash ÷ len(stock_list) | 每只标的独立账户与累计收益基准 |
| 单笔单位资金上限 | per_stock_cash × 0.5 | unit_size clip 上限为半仓(防止单笔买满) |
| 单位股数下限 | min_shares(100) | unit_size clip 下限 |
| 单笔风险 | per_stock_cash × risk_per_trade | 由 N 值与 risk_per_unit 倒推出可买股数 |
四、数据加载与处理详解
4.1 标的(股票/ETF)数据来源优先级
get_stock_data(stock_code) 依次尝试:
- 自定义数据源(
use_custom_data=True且代码在_custom_data_cache)——add_stock_data_from_*注入后优先; - 本地 parquet(
data/历史数据/{代码}.parquet等多路径回退); - 均无 → 返回空 DataFrame,标的被跳过。
加载后统一:日期过滤到 [start_date, end_date]、按日期升序、剔除 close≤0 或 open≤0 行、缺 high/low 用 close 补齐、补算 zdf = close.pct_change()。
4.2 多线程加载
get_all_stock_data() 用 ThreadPoolExecutor(max_workers) 并发加载全部标的;_load_single_stock 要求数据 >50 行才接受(否则视为「数据不足」)。
4.3 指数数据来源
get_index_data() 优先返回注入的自定义指数数据(use_custom_index_data=True 且已注入),否则从本地文件读取 index_stock 对应指数并缓存。指数仅用于输出留档与绩效展示,策略对照基准实际是 calculate_benchmark_curve 生成的等权持有不动曲线。
五、海龟信号与资金管理详解
5.1 唐奇安通道与信号(calculate_turtle_signals)
在 vectorized_backtest 中对每只标的调用 calculate_turtle_signals(df),一次性算出整段:
- 计算
tr(真实波幅)→n_value = tr.ewm(span=n_period).mean(); - 用
entry_period算入市上/下轨(high/low的 rolling max/min 并shift(1)); - 用
exit_period算离市上/下轨; entry_signal:上破入市上轨=1(做多)、下破入市下轨=-1;exit_signal:跌破离市下轨=1(平多)、上破离市上轨=-1;unit_size:按风险公式换算并 clip 到[min_shares, 半仓],转 int;add_price = close + n_value × add_unit_threshold(供主循环加仓判断)。
5.2 入市 / 离市 / 加仓 / 止损规则(vectorized_backtest 主循环)
每个交易日按「①做T → ②离市 → ③止损 → ④入市 → ⑤加仓 → ⑥记账」顺序执行:
| 动作 | 触发条件 | 成交 |
| :--- | :--- | :--- |
| 开多仓 | 无持仓 且 entry_signal==1(突破 entry 日高点) | 买入 1 单位,current_units=1,记录入市价 |
| 加仓 | 有持仓 且 current_units<max_units 且 价≥入市价+N×add_unit_threshold 且 >上次加仓价 | 再买 1 单位,current_units+=1 |
| 平多仓 | 有持仓 且 exit_signal==1(跌破 exit 日低点) | 全部卖出,单位清零 |
| 止损 | 有持仓 且 价≤入市价−2×N | 全部卖出,单位清零 |
| 做T止盈卖出 | 启用做T 且有持仓 且 zdf≥sell_zdf | 卖 trade_value 金额(≤持仓市值30%) |
| 做T止损买入 | 启用做T 且有持仓 且 zdf≤buy_zdf | 买 trade_value 金额(≤可用现金30%) |
5.3 关键口径说明
- 做T的
sell_zdf/buy_zdf是全局的(所有标的共用); - 加仓价取
入市价 + N×阈值(以首单入市价为基准),且需大于上次加仓价才允许再加(防止同价位反复加仓); - 止损固定为
入市价 − 2×N(经典 2N 规则,代码未开放该倍数为参数); - 一旦平多/止损,
entry_price/last_add_price/current_units全部清零,需重新突破才再入市; - 多标的总账户 = 各标的资金池逐日求和,
total_return = 累计盈亏 ÷ cash(总初始资金)。
六、交易执行详解
6.1 买入撮合(calculate_buy_shares)
buy_amount = amount / (1 + comm) # 先扣手续费
shares = 向下取整(buy_amount / price) # 再按 share_multiple(100) 对齐
若 shares < min_shares(100) → 0
实际成本 = shares×price × (1+comm),循环确保 ≤ amount
6.2 卖出撮合(calculate_sell_shares)
卖出时手续费从卖出金额中直接扣除;sell_amount=None 表示全部卖出(海龟离场/止损用)。
6.3 做T下单金额上限
- 做T止盈卖出:
sell_amount = min(trade_value, 持仓市值 × 0.3) - 做T止损买入:
buy_amount = min(trade_value, 可用现金 × 0.3)
6.4 成交记录字段(trade_log)
每笔成交记录:date / stock / type / price / amount / shares / cash_after / holdings_after / reason / zdf / commission。
type 取值:开多仓 / 加仓 / 平多仓 / 止损 / 做T卖出 / 做T买入;reason 示例:突破20日高点 / 跌破10日低点 / 止损 2.00N / 涨幅3.00% / 跌幅-3.00%。
七、完整函数清单
以下为
xg_hg_backtrader类的全部方法,按功能分组。共 59 个方法(含私有方法),无模块级顶层函数。
7.1 构造与配置
| 方法签名 | 说明 |
| :--- | :--- |
| __init__(start_date, end_date, stock_list, ...) | 构造回测实例,配置基础/海龟/做T/数据源参数 |
| _convert_to_serializable(obj) | 将对象(Timestamp/datetime/ndarray/DataFrame/NaN)递归转 JSON 可序列化 |
| get_config() -> dict | 获取当前策略的全部配置参数(含 strategy_type='Turtle Trading System with DT') |
7.2 自定义指数注入(7 种接口)
| 方法签名 | 说明 |
| :--- | :--- |
| add_index_data_from_dataframe(df) | 从 DataFrame 注入指数数据(需 date+close) |
| add_index_data_from_excel(file_path, sheet_name=0, **kwargs) | 从 Excel 注入 |
| add_index_data_from_csv(file_path, **kwargs) | 从 CSV 注入(自动尝试编码) |
| add_index_data_from_json(file_path, orient='records', **kwargs) | 从 JSON 注入 |
| add_index_data_from_dict(data) | 从字典注入 |
| add_index_data_from_parquet(file_path, columns=None, **kwargs) | 从 Parquet 注入 |
| add_index_data_from_bytes(file_bytes, file_type='csv', **kwargs) | 从字节流注入 |
7.3 指数数据管理
| 方法签名 | 说明 |
| :--- | :--- |
| clear_index_data() | 清空自定义指数数据 |
| has_index_data() -> bool | 检查是否有自定义指数数据 |
| get_index_data_info() -> dict | 获取指数数据信息(行数/日期范围等) |
| _normalize_index_dataframe(df) | 标准化指数 DataFrame(日期列识别/排序/剔除 close≤0) |
7.4 自定义标的注入(7 种接口)
| 方法签名 | 说明 |
| :--- | :--- |
| add_stock_data_from_dataframe(stock_code, df) | 从 DataFrame 注入标的日线数据 |
| add_stock_data_from_excel(stock_code, file_path, sheet_name=0, **kwargs) | 从 Excel 注入 |
| add_stock_data_from_csv(stock_code, file_path, **kwargs) | 从 CSV 注入 |
| add_stock_data_from_json(stock_code, file_path, orient='records', **kwargs) | 从 JSON 注入 |
| add_stock_data_from_dict(stock_code, data) | 从字典注入 |
| add_stock_data_from_parquet(stock_code, file_path, columns=None, **kwargs) | 从 Parquet 注入 |
| add_stock_data_from_bytes(stock_code, file_bytes, file_type='csv', **kwargs) | 从字节流注入 |
7.5 自定义标的数据库管理
| 方法签名 | 说明 |
| :--- | :--- |
| clear_custom_data() | 清空所有已注入的自定义标的数据 |
| remove_stock_data(stock_code) | 移除指定标的的自定义数据 |
| get_custom_data_keys() -> list | 获取所有已注入标的代码列表 |
| has_custom_data(stock_code) -> bool | 检查指定标的是否已有自定义数据 |
7.6 数据加载与处理
| 方法签名 | 说明 |
| :--- | :--- |
| _normalize_dataframe(df, stock_code=None) | 标准化 DataFrame(日期列识别、close/high/low/open/volume 补齐、补 zdf/复权因子) |
| get_stock_data(stock_code) | 读取单标的(优先自定义,其次本地 parquet),日期过滤+列补齐 |
| _load_single_stock(stock) | 多线程任务:加载单只标的(>50 行才接受) |
| get_all_stock_data() | 多线程并发加载全部标的 |
| get_index_data() | 获取指数数据(优先自定义,其次本地文件,带缓存) |
7.7 海龟信号与资金管理(核心)
| 方法签名 | 说明 |
| :--- | :--- |
| calculate_benchmark_curve(all_data) | 计算等权持有不动基准净值曲线(各标归一化后求交集日期均值) |
| calculate_turtle_signals(df) | 计算海龟信号:TR/N值/唐奇安通道/入离场信号/unit_size/add_price |
7.8 交易撮合计算
| 方法签名 | 说明 |
| :--- | :--- |
| calculate_buy_shares(amount, price) | 计算买入股数与含费实际成本(先扣费、100 手对齐) |
| calculate_sell_shares(shares, price, sell_amount=None) | 计算卖出股数与实得金额(None=全卖,手续费从卖款扣) |
7.9 回测执行
| 方法签名 | 说明 |
| :--- | :--- |
| vectorized_backtest() | 向量化回测主函数(多标的,含做T),返回组合历史 portfolio_history |
| run_backtest() | 执行完整回测(等价于 vectorized_backtest) |
7.10 绩效与数据生成
| 方法签名 | 说明 |
| :--- | :--- |
| generate_equity_curve_data() | 生成净值曲线(含 net_value/drawdown/position_ratio/基准) |
| generate_trade_data() | 生成成交明细与统计(trades+statistics) |
| generate_position_data() | 生成每日持仓与统计(positions+statistics) |
| generate_account_data() | 生成每日账户与统计(account_history+statistics) |
| calculate_performance_metrics(df, df_index) | 计算核心绩效指标 |
| calculate_annual_performance(portfolio_df, benchmark_dict=None) | 计算年度收益统计 |
7.11 数据获取接口(懒触发,自动 run_backtest)
| 方法签名 | 说明 |
| :--- | :--- |
| get_annual_performance() | 获取年度收益统计 |
| get_annual_performance_df() | 年度收益转 DataFrame |
| get_trade_data() / get_position_data() / get_account_data() | 获取成交/持仓/账户数据 |
| get_daily_positions() / get_trade_log() / get_portfolio_history() | 获取原始日持仓/成交/组合历史(dict records) |
| get_performance_metrics() / get_equity_curve_data() | 获取绩效/净值 |
| get_stock_results() | 获取各标的独立回测结果 |
| get_backtest_summary() | 获取回测摘要(config+绩效+成交+净值+各标的) |
| get_all_data() | 获取全量数据(JSON 可序列化) |
| get_backtrader_data() | 获取按分类组织的回测数据(指数/成交/持股/账户/绩效等) |
7.12 结果保存与报告
| 方法签名 | 说明 |
| :--- | :--- |
| save_backtrader_data(user='test') | 分类保存回测结果到 策略模型/海龟策略/{user}/(Excel+JSON) |
| save_to_json(filename=None, include_raw_data=False) | 保存回测结果为 JSON 文件 |
| generate_report() | 生成格式化文本报告 |
八、输出数据结构详解
8.1 绩效指标字段(performance_metrics)
| 字段 | 类型 | 说明 |
| :--- | :--- | :--- |
| start_date / end_date | str | 回测起止日期 |
| total_days | int | 交易总天数 |
| total_cash | float | 初始总资金 |
| final_value | float | 最终总资产 |
| total_return | float | 总收益率(小数,如 0.25=25%) |
| total_pnl | float | 总盈亏额 |
| total_invested | float | 累计买入投入(开多/加仓成交额) |
| total_commission | float | 累计手续费 |
| remaining_cash / final_holdings | float | 期末现金 / 期末持仓 |
| annual_return | float | 年化收益率 |
| max_drawdown | float | 最大回撤(负数) |
| max_drawdown_date | str | 最大回撤发生日 |
| sharpe_ratio / sortino_ratio / calmar_ratio | float | 夏普 / 索提诺 / 卡玛比率 |
| volatility | float | 年化波动率 |
| win_rate | float | 胜率(日收益为正占比) |
| benchmark_final_value / benchmark_start_value | float | 基准(等权持有)期末/期初净值 |
| benchmark_total_return | float | 基准总收益率 |
| benchmark_max_drawdown | float | 基准最大回撤 |
| excess_return / excess_return_pct | float | 相对基准超额收益(小数/百分比) |
8.2 年度收益统计字段(annual_performance,按年份键)
| 字段 | 类型 | 说明 |
| :--- | :--- | :--- |
| year / start_date / end_date / total_days | int/str | 年份与年度区间 |
| total_cash / final_value / total_pnl | float | 资金 / 期末值 / 年度盈亏 |
| total_return / annual_return | float | 年度总收益率 |
| max_drawdown | float | 年度最大回撤 |
| sharpe_ratio / sortino_ratio / calmar_ratio | float | 年度风险调整收益 |
| win_rate / volatility | float | 年度胜率 / 波动率 |
| benchmark_total_return / benchmark_* | float | 年度基准各项 |
| excess_return / excess_return_pct | float | 年度超额收益 |
8.3 净值曲线字段(equity_curve_data)
| 字段 | 类型 | 说明 |
| :--- | :--- | :--- |
| dates | list | 日期字符串列表 |
| total_value / cumulative_pnl | list | 每日总资产 / 累计盈亏 |
| cash / holdings / investment_cost | list | 现金 / 持仓 / 成本 |
| net_value | list | 策略净值(总资产/初始资金) |
| drawdown | list | 回撤(%) |
| position_ratio | list | 持仓市值占比(%) |
| total_return / daily_return | list | 累计 / 日收益率 |
| benchmark_net_value / benchmark_return | list | 基准净值 / 基准日收益率 |
| statistics | dict | 汇总(起止日/天数/最大最小/总收益/最大回撤) |
8.4 成交统计(trade_data['statistics'])
total_trades / buy_trades / sell_trades / total_buy_amount / total_sell_amount / net_invested / total_commission / first_trade_date / last_trade_date。
8.5 持仓统计(position_data['statistics'])
total_days / max_holdings / min_holdings / final_holdings / avg_holdings / first_date / last_date / final_return;每条 positions 含 stock_details(各标的 price/holdings/value/cash/return/units/n_value)。
8.6 账户统计(account_data['statistics'])
start_date / end_date / total_days / initial_cash / final_total_value / final_cash / final_holdings / total_invested / total_pnl / total_return / max_total_value / min_total_value / max_net_value / min_net_value / volatility,含 benchmark_final_value / benchmark_total_return。
8.7 各标的独立结果(get_stock_results)
每标的含:df(含全部信号列)、cash/holdings/total_value/daily_pnl/cumulative_pnl/investment_cost(数组)、trade_dates/trade_types/trade_prices/trade_amounts/trade_shares/trade_cash_after/trade_holdings_after/trade_reasons/trade_zdf/trade_commission、daily_records(每日 date/price/zdf/现金/持仓/总资产/成本/盈亏/action/units/n_value/entry_price)、以及 final_holdings/final_cash/final_value/final_price/final_return。
8.8 文本报告内容(generate_report())
打印策略配置、绩效指标、各标的表现、年度收益等格式化摘要。
8.9 导出目录结构
策略模型/海龟策略/<user>/
├── 指数数据/ 指数数据.xlsx
├── 成交数据/ 成交数据.xlsx
├── 持股数据/ 持股数据.xlsx
├── 账户数据/ 账户数据.xlsx
├── 绩效指标/ 绩效指标.xlsx
├── 年度收益统计/ 年度收益统计.xlsx
├── 净值曲线/ 净值曲线.json
└── 策略参数/ 策略参数.xlsx
九、完整实战示例
9.1 示例1:经典海龟法则回测(本地数据)
from xg_hg_backtrader.xg_hg_backtrader import xg_hg_backtrader
bt = xg_hg_backtrader(
start_date='20230101',
end_date='20261201',
stock_list=['513100.SH', '513500.SH'],
index_stock='000300.SH',
cash=1000000,
comm=0.0001,
# 经典海龟参数
entry_period=20, # 20日突破入市
exit_period=10, # 10日突破离市
n_period=20, # N值(ATR)20日
risk_per_trade=0.01, # 每笔风险1%
risk_per_unit=0.02, # 单位波动风险2%
max_units=4, # 最多4个单位
add_unit_threshold=0.5, # 每涨0.5N加仓
# 做T
sell_zdf=0.03,
buy_zdf=-0.03,
trade_value=10000,
max_workers=4,
)
result = bt.run_backtest()
print(bt.generate_report())
bt.save_backtrader_data(user="经典海龟")
9.2 示例2:纯海龟(关闭做T)
bt = xg_hg_backtrader(
start_date='20230101',
end_date='20261201',
stock_list=['513100.SH', '513500.SH'],
cash=500000,
entry_period=55, # 长周期(系统2风格)
exit_period=20,
n_period=20,
risk_per_trade=0.01,
max_units=4,
)
bt.enable_dt = False # 关闭做T,仅海龟信号
bt.verbose = True
bt.run_backtest()
print(bt.generate_report())
9.3 示例3:自定义标的数据注入 + 海龟回测
import pandas as pd
bt = xg_hg_backtrader(
start_date='20230101',
end_date='20261201',
stock_list=['513100.SH', '513500.SH'],
cash=1000000,
max_workers=4,
)
# 注入自定义数据(DataFrame 需含 date/open/high/low/close/volume)
# bt.add_stock_data_from_csv('513100.SH', 'data/513100.csv')
# bt.add_stock_data_from_excel('513500.SH', 'data/513500.xlsx')
# bt.add_stock_data_from_dataframe('513100.SH', pd.read_parquet('data/513100.parquet'))
bt.run_backtest()
bt.save_to_json('result/turtle.json')
9.4 示例4:注入自定义指数数据
bt = xg_hg_backtrader(
start_date='20230101',
end_date='20261201',
stock_list=['513100.SH'],
cash=500000,
)
# 构造或读取指数 DataFrame(含 date/close 即可)
import pandas as pd
index_df = pd.read_parquet('data/my_index.parquet') # 需 date/close 列
bt.use_custom_index_data = True
bt.add_index_data_from_dataframe(index_df)
print("是否有指数:", bt.has_index_data(), bt.get_index_data_info())
bt.run_backtest()
print(bt.generate_report())
9.5 示例5:提取结果做二次分析 + 画净值/回撤曲线
bt.run_backtest()
metrics = bt.get_performance_metrics()
curve = bt.get_equity_curve_data()
trades = bt.get_trade_data()
print(f"总收益率: {metrics['total_return']*100:.2f}%")
print(f"年化收益率: {metrics['annual_return']*100:.2f}%")
print(f"最大回撤: {metrics['max_drawdown']*100:.2f}%")
print(f"夏普比率: {metrics['sharpe_ratio']:.3f}")
print(f"胜率: {metrics['win_rate']*100:.2f}%")
print(f"交易笔数: {trades['statistics']['total_trades']}")
import matplotlib.pyplot as plt
dates = curve['dates']
plt.figure(figsize=(12, 5))
plt.plot(dates, curve['net_value'], label='策略净值', linewidth=2)
if curve.get('benchmark_net_value'):
plt.plot(dates, curve['benchmark_net_value'], label='基准(等权持有)', linestyle='--')
plt.legend(); plt.xticks(rotation=45); plt.tight_layout(); plt.show()
9.6 示例6:按标的查看海龟信号与回测明细
bt.run_backtest()
# 各标的独立结果(含每日 units/n_value/entry_price/action)
for stock, res in bt.get_stock_results().items():
print(f"=== {stock} ===")
print(f" 期末资产: {res['final_value']:.2f}, 收益率: {res['final_return']*100:.2f}%")
# 查看某标的最后一个交易日的海龟状态
stock = '513100.SH'
res = bt.get_stock_results()[stock]
last = res['daily_records'][-1]
print(f"{stock} 末日 units={last['units']}, N={last['n_value']:.4f}, entry={last['entry_price']:.4f}")
# 年度绩效
print(bt.get_annual_performance())
十、自定义数据详解
10.1 标的注入后系统自动做的事
add_stock_data_from_* 会调用 _normalize_dataframe:识别日期列/索引→排序→补齐 close/high/low/open/volume→补 zdf→(有 preClose 时)补 return/adj_factor。注入成功后 use_custom_data 应设为 True(多数方法自动切换)。
10.2 指数注入说明
add_index_data_from_* 会调用 _normalize_index_dataframe,只需 date+close(自动剔除 close≤0、识别日期列);注入后 use_custom_index_data=True 时优先作为指数基准。
10.3 注入成功判定与验证
print("标的自定义键:", bt.get_custom_data_keys()) # 含代码即成功
print("has_custom_data:", bt.has_custom_data('513100.SH'))
print("指数:", bt.has_index_data(), bt.get_index_data_info())
十一、常见问题与 FAQ
Q1: 提示「数据文件不存在」或标的被跳过?
检查 data/历史数据/ 下是否有 {代码}.parquet;或使用 add_stock_data_from_* 注入。海龟还要求数据 >50 行且 n ≥ max(entry,exit,n)+10,数据太短会无信号被跳过。
Q2: 某标的没有任何入市信号?
多为突破周期内始终未创 entry_period 日新高(横盘/下跌行情),属海龟策略的正常表现(趋势跟踪在震荡市少交易)。可调小 entry_period 提高灵敏度。
Q3: 为什么回测交易次数很少?
海龟是低频率趋势跟踪,只在大突破时开仓。若想更多交易:调小 entry_period/exit_period、缩短回测标的到波动大的品种,或调小 add_unit_threshold 加速加仓。
Q4: 如何关闭做T只看纯海龟?
bt.enable_dt = False 即可;或把 sell_zdf 设极大、buy_zdf 设极小避免触发。
Q5: 自定义数据注入后仍走本地目录?
确认注入返回 True,用 get_custom_data_keys() 验证,并把 use_custom_data=True(或确认注入方法自动切换)。
Q6: 收益率为 0 或异常?
检查价格列是否全为正、cash 初始值、stock_list 是否都有数据、成交撮合是否因手续费过高导致 actual_cost>amount 而 0 股。
Q7: 海龟单笔最大风险是多少?
per_stock_cash × risk_per_trade(默认 1%×每标资金)。实际换算成股数时受 unit_size 的 [min_shares, 半仓] clip 限制,小资金可能买不足理论单位。
Q8: 做T会频繁加仓导致仓位失控吗?
做T止损买入有 ≤可用现金30% 上限,且做T每标的每日最多各触发一次(zdf 阈值控制),叠加 max_units 限制,仓位风险可控。
十二、高级技巧与二次开发
12.1 参数调优建议
| 参数 | 建议范围 | 说明 |
| :--- | :--- | :--- |
| entry_period | 20-55 | 越小越敏感(系统1),越大越滞后(系统2长周期) |
| exit_period | 10-20 | 应小于 entry_period,控制离场及时性 |
| n_period | 10-30 | N 值平滑窗口,越大越平稳 |
| risk_per_trade | 0.005-0.02 | 单笔风险,越小单笔越小 |
| max_units | 3-8 | 金字塔层级上限 |
| add_unit_threshold | 0.25-1.0 | 加仓所需 N 倍数,越小加仓越密 |
12.2 海龟策略设计经验
- 突破确认:入市/离市均用
shift(1)前置数据,避免未来函数,务必保留。 - 波动适配:海龟用 N 值自动适配标的波动率,可直接混合高/低波动标的而无需手工归一。
- 趋势过滤:可在
calculate_turtle_signals中叠加长期均线方向过滤,减少横盘假突破。
12.3 自定义海龟规则
继承 xg_hg_backtrader,重写以下核心方法:
class MyTurtle(xg_hg_backtrader):
def calculate_turtle_signals(self, df):
"""自定义信号:加入均线方向过滤后再调父类"""
df = super().calculate_turtle_signals(df)
# 例如:仅当 close > MA(close, 200) 才允许 entry_signal=1
ma200 = df['close'].rolling(200).mean()
df.loc[df['close'] < ma200, 'entry_signal'] = 0
return df
12.4 自定义交易/成本规则
重写 calculate_buy_shares(改买入逻辑)、calculate_sell_shares(改卖出/全卖逻辑)、或 calculate_performance_metrics(加自定义绩效指标)。
十三、技术说明与提示
- 多资金池:每标独立
per_stock_cash = cash ÷ len(stock_list),组合累计收益率按总初始资金cash折算。 - 无模块级函数:全部逻辑在类内,59 个方法覆盖信号/撮合/绩效全流程。
- 符号约定:
sell_zdf为正涨幅阈值(止盈),buy_zdf为负跌幅阈值(补仓),勿写反。 - 指数数据仅用于输出留档,策略对照基准为「等权持有不动」曲线(
calculate_benchmark_curve)。 - 源码当前固定
adj_type='none'、use_long_system=False(仅做多),若需复权或做空需二次开发。 - 做T参数
sell_zdf/buy_zdf是全局的(所有标的共用)。
小果海龟交易策略回测系统,让海龟法则落地更高效、更透明。如需源码、更多因子库或技术支持,欢迎联系小果(微信:xg_quant)。
微信扫一扫