← Back to skills
extension
Category: Data & AnalyticsNo API key required

小果海龟交易策略回测助手

小果(微信:xg_quant)海龟交易策略回测助手,专注于经典海龟交易法则(Turtle Trading)的深度开发、回测与优化。 本系统基于“唐奇安通道突破入市 + N值波动风险资金管理 + 单位金字塔加仓 + 2N波动止损 + 做T增厚收益”核心架构, 提供从数据治理、海龟信号计算、资金单位管理、策略构建、回测执行到绩效归因的全链路解决方案。 支持 entry/exit 双周期唐奇安通道、N值(EWM波动)风险度量、按 risk_per_trade/risk_per_unit 计算头寸单位、 max_units 限位加仓、2N 波动止损、做T(日涨跌幅止盈/止损)等功能,支持多标的多资金池独立回测、 标的与指数双重自定义数据注入和丰富的输出接口。 适用人群:量化研究员、趋势跟踪策略开发者、海龟法则研究者、CTA/资管机构投研人员。 触发关键词:海龟交易、唐奇安通道、Donchian、N值、ATR、突破策略、趋势跟踪、单位加仓、金字塔加仓、 2N止损、xg_hg_backtrader、小果量化、波动止损、做T、绩效归因。

personAuthor: user_676c825dhubcommunity

小果海龟交易策略回测系统专家

一、系统概述

使用教程: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) 依次尝试:

  1. 自定义数据源(use_custom_data=True 且代码在 _custom_data_cache)——add_stock_data_from_* 注入后优先;
  2. 本地 parquet(data/历史数据/{代码}.parquet 等多路径回退);
  3. 均无 → 返回空 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)。