小果均值方差回测系统助手

SKILL效率
效率 未标注权限 许可证不明确
安装这个技能

小果(微信:xg_quant)均值方差最优资产组合权重再平衡策略回测助手,专注于现代投资组合理论(MPT/马科维茨均值-方差模型)的深度开发、回测与优化。 本系统基于“历史收益回看 → 均值方差优化(最大化夏普比率) → 定期权重再平衡”核心架构, 提供从数据治理、收益率矩阵构建、最优权重求解、组合再平衡交易、回测执行到绩效归因的全链路解决方案。 支持 lookback_days 历史回看窗口、SLSQP 均值方差优化(最大化夏普比率)、min/max 单标权重约束、 interval 交易日定期调仓、等权持有不动基准对照、标的与指数双重自定义数据注入和丰富的输出接口。 适用人群:量化研究员、资产配置研究者、现代组合理论(MPT)研究者、FOF/资产管理机构投研人员。 触发关键词:均值方差、马科维茨、Markowitz、MPT、最优资产组合、权重再平衡、夏普比率最大化、 SLSQP、协方差矩阵、资产配置、xg_mean_var_backtrader、小果量化、lookback、调仓、权重历史。

一句话选型结论

按资料字段整理

小果均值方差回测系统助手是效率类的 Agent Skill,安装方式未标注,权限级别未标注,许可证不明确,有可直接复制的安装命令。技能本质是给模型读的说明书,效果取决于模型与客户端;装完先用一个小任务验证,再放进正式流程。

分类效率 安装方式未标注 权限级别未标注权限 许可证许可证不明确
累计安装 未标注 本周 未标注
GitHub 星标 未标注 仓库 未标注
下载量 未标注 技能市场下载数
权限级别 未标注权限 安装前请确认风险范围
许可证 许可证不明确 未说明

安装

未标注
在支持 Skills 的客户端里执行,装完问一句「你有哪些技能」验证
skillhub install user_676c825d/xg-mean-var-backtrader
  1. 1
    确认客户端支持

    确认你的客户端支持 Skills(Claude、Codex、Cursor 等),并升级到较新的版本。

  2. 2
    拿到技能文件

    执行上面的命令安装;也可以把仓库里的 SKILL.md 手动放进客户端的 skills 目录。

  3. 3
    刷新技能列表

    重新打开客户端,或刷新技能列表,让新放进来的技能被加载。

  4. 4
    验证是否生效

    问一句「你有哪些技能」,确认列表里出现它,再拿一个小任务试跑。

技能档案

效率
字段来自技能仓库与公开索引,中文说明由本站标注
作者 / 维护方user_676c825d仓库 未标注 · 版本 未标注
宿主客户端未标注技能可被这些客户端加载
安装方式未标注安装包 community
权限级别未标注权限安装前请确认风险范围
许可证未说明许可证不明确,商用前请自行确认条款
仓库可用性available技能仓库当前是否可访问
最近核验2026-11-06上游最后核验时间 · 数据更新 2026-11-06
正文体量40.3 KBSKILL.md 原文大小,越大说明说明书写得越细

典型使用场景

3 类
按分类整理的常见用法,具体以 SKILL.md 为准
整理待办与日程

把零散任务收进清单,排出优先级。

批量处理重复任务

把固定动作做成模板,重复执行。

把流程写成清单

把口头流程整理成可复用的步骤。

选择建议

装之前先看这几条
按条目字段给出的判断,不替你决定用不用

值得选的地方

  • 有可直接复制的安装命令,不用自己翻文档找入口。

先想清楚的地方

  • 没有标注权限级别,实际能做什么要装好后确认。
  • 许可证不明确,商用或二次分发前先到仓库确认条款。
  • 没有做站内核验,内容以作者仓库为准。
  • 技能只是说明书,实际效果取决于模型与客户端,装完先用小任务试一遍。

更适合

  • 需要在效率场景里给模型补一套做法的人。
  • 愿意先读一遍 SKILL.md、确认它会让模型做什么的人。

不太适合

  • 对许可证要求很严、必须明确可商用的人。
  • 只想装完就自动变强、不打算看说明书的人。

同类对比

6 个同类
同分类里挑最接近的几条,字段以各自详情页为准
技能权限级别安装方式累计安装宿主客户端安装命令
小果均值方差回测系统助手当前 未标注权限 未标注 未标注 未标注 有
Nano PDF 文档 联网访问 ClawHub 市场 424.9 万 OpenClaw 有
自动更新程序 浏览器控制 ClawHub 市场 296.4 万 OpenClaw 有
Gemini 助手 联网访问 ClawHub 市场 254.7 万 OpenClaw 有
word DOCX 文档 联网访问 ClawHub 市场 239.6 万 OpenClaw 有
Excel XLSX 前端 联网访问 ClawHub 市场 227.0 万 OpenClaw 有

SKILL.md 全文

40.3 KB
模型实际读到的说明书原文,来自技能仓库

小果均值方差回测系统专家

一、系统概述

使用教程:https://gitcode.com/qq_50882340/xg_mean_var_backtrader

1.1 系统定位

小果均值方差最优资产组合权重再平衡回测系统(xg_mean_var_backtrader)是一套忠实还原马科维茨现代投资组合理论(Modern Portfolio Theory, MPT)的专业级量化资产配置回测框架。它以「过去 lookback_days 天的历史收益率」估计各资产的期望收益与协方差矩阵,通过「均值方差优化(SLSQP 最大化夏普比率)」在每只标的权重限制 [min_weight, max_weight] 内求解当期最优资产权重,随后每 interval 个交易日将实际持仓再平衡到该目标权重,把「该买多少 / 该卖多少」由量化出的组合风险收益最优解来界定。

与其它策略系统最大的不同在于:均值方差系统不做择时、不靠单标的方向判断,而是聚焦组合层面的资产配置——把资金在多个低相关资产间按「期望收益÷波动风险」最优配比,在给定风险偏好约束下最大化单位风险所获得的超额回报(夏普比率)。单一资金池整体运作(不把 cash 均分到各标的),每日记录各标的实际/目标权重,交易类型为「初始建仓」与「再平衡买入/卖出」,无做T、无止损止盈概念。

> 均值方差核心思想:不要把鸡蛋放在一个篮子里,且每个篮子的大小应由「收益÷风险」的科学配比而非拍脑袋决定。 组合的风险不仅取决于各资产自身波动,更取决于资产间的协方差(相关性)——低相关资产的搭配可在不牺牲太多收益的前提下显著降低组合波动。

1.2 核心策略逻辑(每 interval 交易日执行)

均值方差框架在每个共同交易日的运行分两阶段:组合初始化(一次性) 与 定期再平衡(每 interval 日):

一、组合初始化(首个共同交易日)
  ① 等权重初始建仓:按 stock_list 等分资金买入各标的(不足 1 手则跳过)
  ② 目标权重置为等权,调仓计数归零

二、每日主循环(遍历每个共同交易日)
  ① 当日市值 = 各标的 持仓 × 收盘价;总资产 = 现金 + 市值
  ② 若有当日最优权重 → 更新 target_weights
  ③ 每累计 interval 个交易日且总资产>0 → 触发再平衡:
     ├─ 对每只标的:target_value = 总资产 × target_weight
     ├─ diff = target_value − 当前市值
     ├─ |diff| < 总资产×0.5% → 忽略(避免频繁小额交易)
     ├─ diff>0 → 再平衡买入(≤可用现金)
     └─ diff<0 → 按金额卖出(回收现金)
  ④ 记录每日:现金/持仓/市值/总资产/累计盈亏/各标的实际与目标权重
  ⑤ 依序补齐每日收益率/盈亏,并对照等权持有不动基准

每个 interval 个交易日对每只标的最多买卖一次;单日可多标的同时调仓;动作类型记录为「初始建仓 / 再平衡买入 / 再平衡卖出」。

1.3 均值方差优化引擎(关键概念)

均值方差系统的一切围绕「收益率矩阵」与「协方差风险」两个核心,权重由最大化夏普比率的最优化求得:

概念 公式/算法 说明
对齐数据 取各标的共同交易日期交集 align_data 只保留全部标的同时有行情的日期,用于可比的收益/协方差计算
收益率矩阵 对齐后各标的 zdf 列(日涨跌幅) get_returns_matrix 截取 end_date 前最近 lookback_days 天
期望收益 mean_returns = 日收益均值 × 252 年化期望收益估计
协方差矩阵 cov = 日收益协方差 × 252 年化协方差,捕捉资产间相关结构
目标函数 negative_sharpe = −(期望收益−rf) ÷ 组合波动 rf 默认 0.02(2%),最小化负夏普 = 最大化夏普
求解器 scipy.optimize.minimize(method='SLSQP') 在约束内求最优权重,maxiter=1000
权重约束 各权重 ∈ [min_weight, max_weight] 且 总和=1 避免单标过度集中/过度分散
初始猜测 等权 1/n 迭代起点为平均配置
兜底 数据<30行 或 优化失败 → 退回等权 保证总有可用权重

> ⚠️ 权重优化用 zdf(日涨跌幅) 作为收益率代理、zdf.cov() 作为协方差来源;求解为无放空(weights 归零后归一化)的纯多头均值方差配置。
>
> 📌 注意:lambda_risk(风险厌恶系数)在当前版本只作参数存储/打印留档,并未直接进入 SLSQP 目标函数——实际求解目标是最大化夏普比率(negative_sharpe),而非 max return − lambda×risk 形式。如需风险厌恶形式可二次开发 optimize_max_sharpe。

1.4 现代组合理论(MPT) → 本框架参数映射

MPT/资产配置概念(理论) 本框架参数 默认 说明
历史样本期估计 lookback_days 60 用过去 N 个交易日估计收益/协方差
组合再平衡频率 interval 5 每 N 个交易日调一次仓
单标的最大配比上限 max_weight 0.6 任意标的不超组合 60%
单标的最小配比下限 min_weight 0.05 任意标的至少配置 5%
风险厌恶程度 lambda_risk 2.0 本版仅留档,未直接进目标函数
无风险利率 rf(优化内固定) 0.02 negative_sharpe 中超额收益的减项
权重和为 1 (约束硬性) 1 资金全仓分配,不保留目标现金
调仓死区 总资产×0.5% 0.005 |diff| 低于此忽略,避免过度交易

1.5 设计哲学

  • 解耦与复用:数据对齐(align_data)、收益矩阵(get_returns_matrix)、优化目标(negative_sharpe)、求解(optimize_max_sharpe)、逐期权重(calculate_optimal_weights_ts)与交易撮合各环节解耦,可独立替换。
  • 透明与可解释:每个调仓日记录目标权重/前权重/买卖权重差,weight_history 完整留存每日权重演变,决策可追溯。
  • 风险优先:以协方差与组合波动作为约束标尺,追求「单位风险下最高收益」,天然适应不同波动率资产搭配。
  • 灵活与扩展:支持自定义数据注入(标的+指数各 7 种接口)、lookback/interval/weight 边界 全参数化,可继承重写 optimize_max_sharpe 引入风险厌恶/无放空变体。

二、安装与运行环境

2.1 安装包

小果均值方差回测系统以单个类文件 xg_mean_var_backtrader.py 形式提供,无独立安装步骤。将脚本置于工作目录后,在同一目录(或旁路)下放置数据文件即可使用。

使用教程:https://gitcode.com/qq_50882340/xg_mean_var_backtrader

2.2 依赖

  • Python ≥ 3.8
  • 第三方库:pandas、numpy、scipy(均值方差优化与统计必需)
  • 本地数据源可选依赖:pyarrow(读取 .parquet 历史数据)
  • 无需安装 xg_tdx_func(本框架不涉及通达信公式引擎)

> ⚠️ 本系统强依赖 scipy(from scipy.optimize import minimize、from scipy import stats),与其它小果回测系统不同,务必安装 scipy。

安装依赖:

pip install pandas numpy scipy pyarrow

2.3 包结构

工作目录/
├── xg_mean_var_backtrader.py   # 主类文件(class xg_mean_var_backtrader)
├── data/
│   ├── 历史数据/              # 本地标的日线 parquet(代码.parquet)
│   └── (可选) 指数历史文件     # 指数数据(未注入自定义指数时)
└── 策略模型/
    └── 均值方差最优资产组合策略/&lt;user&gt;/  # save_backtrader_data 导出目录(自动创建)

2.4 导入方式

from xg_mean_var_backtrader.xg_mean_var_backtrader import xg_mean_var_backtrader

bt = xg_mean_var_backtrader(
    start_date=&#x27;20230101&#x27;,
    end_date=&#x27;20261201&#x27;,
    stock_list=[&#x27;159915.SZ&#x27;, &#x27;513100.SH&#x27;, &#x27;518880.SH&#x27;],
    cash=1000000,
)

2.5 数据目录要求(使用内置数据源时)

当未注入自定义数据(use_custom_data=False)时,系统按固定路径查找单只标的日线 parquet:

data/历史数据/{stock_code}.parquet

找到即用;找不到该标的则加载失败并在结果中跳过。

2.6 数据字段要求

标的(股票/ETF)日线数据需包含以下字段:

字段 说明 是否必须
date 交易日期 ✅ 必须
close 收盘价 ✅ 必须(>0)
open 开盘价 ✅ 必须(>0)
high 最高价 ✅ 必须(缺失自动=close/NaN)
low 最低价 ✅ 必须(缺失自动=close/NaN)
volume 成交量 ✅ 必须
zdf 涨跌幅 ⚠️ 推荐(缺失自动用 close.pct_change() 补)
preClose 前收盘价 ⚠️ 可选(有则补 return/adj_factor)
amount 成交金额 ⚠️ 可选
证券代码 / 证券名称 代码/名称 ⚠️ 可选(自动补)

> 均值方差优化核心只用到 date + close + zdf;align_data 需各标的存在共同交易日期(交集非空),否则回测终止。数据行数至少需 > lookback_days + 30(calculate_optimal_weights_ts 要求历史≥30 行才跑优化,否则一直退回等权)效果最佳。

指数数据仅需 date + close(close&gt;0),用于输出留档。

三、初始化参数完整参考

> 以下为 __init__ 方法全部参数的详细说明,按功能分组。

3.1 基础参数 (Base)

参数 类型 默认值 说明
start_date str &#x27;20260101&#x27; 回测起始日期,格式 YYYYMMDD
end_date str &#x27;20500101&#x27; 回测结束日期,格式同上
stock_list list [&#x27;159915.SZ&#x27;,&#x27;513100.SH&#x27;,&#x27;518880.SH&#x27;] 候选资产池,元素需带交易所后缀
index_stock str &#x27;000300.SH&#x27; 基准指数代码(用于输出留档)
cash float 100000 初始总资金(元,整体组合资金池,不均分)
comm float 0.0001 手续费率(万1 = 0.0001)
max_workers int 4 数据加载并发线程数
verbose bool False 是否打印加载过程日志(构造末尾强制置 True)

3.2 均值方差优化参数 (Mean-Variance)

参数 类型 默认值 说明
lookback_days int 60 估计收益/协方差的历史回看天数
max_weight float 0.6 单标的目标权重上限
min_weight float 0.05 单标的目标权重下限
lambda_risk float 2.0 风险厌恶系数(本版仅留档/打印,不直接进目标函数)
interval int 5 再平衡周期(每 N 个交易日调一次仓)

3.3 数据源开关 (Data Source)

参数 类型 默认值 说明
use_custom_data bool False 是否使用注入的自定义标的数据库(自动切换)
use_custom_index_data bool False 是否使用注入的自定义指数数据(自动切换)

3.4 内部固定参数(构造时自动设置,一般不修改)

参数 默认值 说明
adj_type &#x27;none&#x27; 复权类型(当前固定 none)
min_shares 100 单笔最小成交份数(1 手)
share_multiple 100 成交份数整数倍(按 100 手撮合)

3.5 关键口径:整体资金池与再平衡死区

概念 公式 说明
初始建仓 现金 = cash,各标的目标 = 等权 1/n 首日一次性全仓等权买入
单标目标市值 total_asset × target_weight 再平衡日的期望持仓市值
再平衡死区 |diff| &lt; total_asset × 0.005 差异过小忽略,避免频繁小额交易
目标现金 0 资金全部分配到标的(权重和为 1),无目标现金保留
权重约束 Σweight=1 且 每只∈[min,max] SLSQP 硬约束

四、数据加载与处理详解

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 行、补算 zdf = close.pct_change().fillna(0)。

4.2 多线程加载与对齐

get_all_stock_data() 用 ThreadPoolExecutor(max_workers) 并发加载全部标的;_load_single_stock 仅要求非空 DataFrame。

align_data(all_data) 取全部标的共同交易日交集,产出对齐宽表:date + {code}_close + {code}_zdf。交集为空则回测终止。这是组合可比的基石——某只标的数据缺失日期过多会显著缩小回测区间。

4.3 指数数据来源

get_index_data() 优先返回注入的自定义指数数据(use_custom_index_data=True 且已注入),否则从本地文件读取 index_stock 对应指数并缓存。指数仅用于输出留档,策略对照基准实际是 calculate_benchmark_curve 生成的等权持有不动曲线。

五、均值方差优化详解

5.1 对齐与收益率矩阵(align_data / get_returns_matrix)

在 vectorized_backtest 中:先 align_data(all_data) 对齐共同日期;get_returns_matrix 从对齐表中取最近 lookback_days 天的 {code}_zdf 列(剔除缺列与 dropna),得到收益率矩阵(列=标的,行=交易日),供优化求解。

5.2 最优权重求解(optimize_max_sharpe)

对收益率矩阵:

  • mean_returns = 各列均值 × 252(年化期望收益);
  • cov_matrix = 协方差 × 252(年化协方差);
  • 目标 negative_sharpe(weights):组合收益=(w·μ),组合波动=√(wᵀΣw),sharpe=(组合收益−rf)/组合波动,返回 −sharpe 供最小化(rf 固定 0.02);
  • 约束:Σweights = 1(eq),每个权重 ∈ [min_weight, max_weight](bounds);
  • 初值等权 1/n,scipy.optimize.minimize(method=&#x27;SLSQP&#x27;, maxiter=1000);
  • 成功 → 结果权重 clip≥0 后归一化返回;失败 → 返回 None。

5.3 逐日权重时间序列(calculate_optimal_weights_ts)

遍历对齐表,对每个调仓参考日用「当日之前全部历史」求解该日最优权重;数据不足 30 行或求解失败 → 该日权重退回等权。产出一张 weight_df(列 = date + 各标的),即每日最优目标权重历史,存为 self.weight_history。

5.4 权重边界与再平衡执行口径

口径 说明
目标权重来源 weight_map[trade_date](按日期查表,缺则沿用上一目标权重)
触发频率 rebalance_counter % interval == 0 才调仓
买入金额 min(diff, 可用现金),撮合不足 1 手则跳过
卖出金额 abs(diff),按金额撮合(不超持仓)
交易死区 |diff| &lt; 总资产×0.5% 忽略

六、交易执行详解

6.1 买入撮合(calculate_buy_shares)

buy_amount = amount / (1 + comm)      # 先扣手续费
shares = 向下取整(buy_amount / price)  # 再按 share_multiple(100) 对齐
若 shares &lt; min_shares(100) → 0
实际成本 = shares×price × (1+comm),循环确保 ≤ amount

6.2 卖出撮合(calculate_sell_shares_by_value)

按金额卖出:sell_shares 由 sell_value÷price 按 100 对齐,上界为持仓;actual_amount = 卖出额 − 手续费。用于再平衡卖出,不提供全仓卖出参数(卖出额由目标权重差值决定)。

6.3 成交记录字段(trade_log)

每笔成交记录:date / stock / type / price / shares / amount / commission / reason。

type 取值:初始建仓 / 再平衡买入 / 再平衡卖出;reason 示例:初始建仓,目标权重33.3%、目标权重40.0%,前权重25.0%,买入权重15.0%、目标权重20.0%,前权重35.0%,卖出权重15.0%。

> 📌 与信号类策略不同,本系统无手续费字段 zdf/做T 概念;每笔统一含 commission 字段。

七、完整函数清单

> 以下为 xg_mean_var_backtrader 类的全部方法,按功能分组。共 63 个方法(含私有方法),无模块级顶层函数。

7.1 构造与配置

方法签名 说明
__init__(start_date, end_date, stock_list, ...) 构造回测实例,配置基础/均值方差/数据源参数
_convert_to_serializable(obj) 将对象(Timestamp/datetime/ndarray/DataFrame/NaN)递归转 JSON 可序列化
get_config() -&gt; dict 获取当前策略的全部配置参数(含 lookback/max_weight/interval 与数据源状态)

7.2 自定义标的注入(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=&#x27;records&#x27;, **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=&#x27;csv&#x27;, **kwargs) 从字节流注入

7.3 自定义标的数据库管理

方法签名 说明
clear_custom_data() 清空所有已注入的自定义标的数据
remove_stock_data(stock_code) 移除指定标的的自定义数据
get_custom_data_keys() -&gt; list 获取所有已注入标的代码列表
has_custom_data(stock_code) -&gt; bool 检查指定标的是否已有自定义数据

7.4 自定义指数注入(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=&#x27;records&#x27;, **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=&#x27;csv&#x27;, **kwargs) 从字节流注入

7.5 指数数据管理

方法签名 说明
clear_index_data() 清空自定义指数数据
has_index_data() -&gt; bool 检查是否有自定义指数数据
get_index_data_info() -&gt; dict 获取指数数据信息(行数/日期范围等)

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) 多线程任务:加载单只标的(非空即接受)
get_all_stock_data() 多线程并发加载全部标的
get_index_data() 获取指数数据(优先自定义,其次本地文件,带缓存)

7.7 均值方差优化(核心)

方法签名 说明
align_data(data_dict) 对齐所有标的数据到共同交易日(交集),产出 {code}_close/{code}_zdf 宽表
get_returns_matrix(data_dict=None, end_date=None, lookback_days=None) 构建收益率矩阵(截取 end_date 前最近 lookback 天,剔除缺列)
negative_sharpe(weights, mean_returns, cov_matrix, rf=0.02) 负夏普比率(供 minimize 最小化)
optimize_max_sharpe(returns_df) SLSQP 最大化夏普求解最优权重(含 min/max bounds + 和=1 约束)
calculate_optimal_weights_ts(aligned_data) 逐期时间序列计算每日最优权重(不足30行/失败退回等权)
calculate_benchmark_curve(all_data, aligned_dates) 计算等权重持有不动基准曲线

7.8 交易撮合计算

方法签名 说明
calculate_buy_shares(amount, price) 计算买入份额与含费实际成本(先扣费、100 手对齐)
calculate_sell_shares_by_value(shares, price, sell_value) 按金额计算卖出份额与实得金额(不超持仓、扣手续费)

7.9 回测执行

方法签名 说明
vectorized_backtest() 向量化回测主函数(初始建仓 + interval 定期再平衡 + 每日记账),返回组合历史 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) 计算年度收益统计

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_weight_history() 获取每日最优权重历史(DataFrame:date+各标的列)
get_backtest_summary() 获取回测摘要(config+绩效+年度+成交+净值+各标的+权重)
get_all_data() 获取全量数据(JSON 可序列化)
get_backtrader_data() 获取按分类组织的回测数据(指数/成交/持股/账户/绩效/权重等)

7.12 结果保存与报告

方法签名 说明
save_backtrader_data(user=&#x27;test&#x27;) 分类保存回测结果到 策略模型/均值方差最优资产组合策略/{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_commission float 累计手续费
remaining_cash / final_holdings float 期末现金 / 期末总持仓份数
annual_return float 年化收益率
max_drawdown float 最大回撤(负数)
max_drawdown_date str 最大回撤发生日
sharpe_ratio / sortino_ratio / calmar_ratio float 夏普 / 索提诺 / 卡玛比率
win_rate float 胜率(日收益为正占比)
volatility float 年化波动率
benchmark_final_value / benchmark_start_value float 基准(等权持有)期末/期初净值
benchmark_total_return float 基准总收益率
benchmark_max_drawdown float 基准最大回撤
excess_return / excess_return_pct float 相对基准超额收益(小数/百分比)
interval / lookback_days / max_weight / min_weight / lambda_risk float/int 优化参数留档

8.2 年度收益统计字段(annual_performance,按年份键)

字段 类型 说明
year / start_date / end_date / total_days int/str 年份与年度区间
total_return / annual_return / total_pnl / final_value float 年度收益指标
max_drawdown / volatility float 年度风险指标
sharpe_ratio / sortino_ratio / calmar_ratio float 年度风险调整收益
win_rate / t_trades / total_commission float/int 年度胜率 / 成交笔数 / 手续费
benchmark_total_return / benchmark_* float 年度基准各项
excess_return / excess_return_pct float 年度超额收益
remaining_cash / final_holdings / total_cash float 年度末资金/持仓/初始资金

8.3 净值曲线字段(equity_curve_data)

字段 类型 说明
dates list 日期字符串列表
total_value / cumulative_pnl list 每日总资产 / 累计盈亏
cash / holdings / market_value list 现金 / 持仓 / 市值
net_value list 策略净值(总资产/初始资金)
drawdown list 回撤(%)
position_ratio list 持仓市值占比(%)
total_return / daily_return list 累计 / 日收益率
benchmark_net_value / benchmark_return list 基准净值 / 基准日收益率
statistics dict 汇总(起止日/天数/初始/最大最小值/总收益/最大回撤)
benchmark_statistics dict 基准汇总(起止净值/总收益/最大回撤)

8.4 成交统计(trade_data['statistics'])

total_trades / buy_trades / sell_trades / total_buy_amount / total_sell_amount / 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/cash/market_value/weight/target_weight)。

8.6 账户统计(account_data['statistics'])

start_date / end_date / total_days / initial_cash / final_total_value / final_cash / final_holdings / 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_weight_history)

DataFrame:列 = date + {各标的代码};每行给出该共同交易日的最优目标权重(和为 1)。是均值方差系统独有的核心诊断输出。

8.8 各标的独立结果(get_stock_results)

每标的含:cash / holdings / total_value(每日数组)、trades(该标成交)、以及 final_holdings / final_cash / final_value。

8.9 文本报告内容(generate_report())

打印策略配置、绩效指标、各标的表现、年度收益表格(含夏普/索提诺/卡尔玛/胜率/基准/超额)。

8.10 导出目录结构

策略模型/均值方差最优资产组合策略/&lt;user&gt;/
├── 指数数据/  指数数据.xlsx + 指数数据.json
├── 成交数据/  成交数据.xlsx + 成交数据.json
├── 持股数据/  持股数据.xlsx + 持股数据.json
├── 账户数据/  账户数据.xlsx + 账户数据.json
├── 绩效指标/  绩效指标.xlsx + 绩效指标.json
├── 年度收益统计/  年度收益统计.xlsx + 年度收益统计.json
├── 净值曲线/  净值曲线.json
├── 策略参数/  策略参数.xlsx + 策略参数.json
└── 权重历史/  权重历史.xlsx + 权重历史.json   ← 本系统独有

九、完整实战示例

9.1 示例1:经典均值方差再平衡回测(本地数据)

from xg_mean_var_backtrader.xg_mean_var_backtrader import xg_mean_var_backtrader

bt = xg_mean_var_backtrader(
    start_date=&#x27;20230101&#x27;,
    end_date=&#x27;20261201&#x27;,
    stock_list=[&#x27;159915.SZ&#x27;, &#x27;513100.SH&#x27;, &#x27;518880.SH&#x27;],
    index_stock=&#x27;000300.SH&#x27;,
    cash=1000000,
    comm=0.0001,
    # 均值方差优化参数
    lookback_days=60,     # 用过去60日估计收益/协方差
    max_weight=0.6,       # 单标权重上限60%
    min_weight=0.05,      # 单标权重下限5%
    lambda_risk=2.0,      # 风险厌恶(留档)
    interval=5,           # 每5个交易日调仓
    max_workers=4,
)

result = bt.run_backtest()
print(bt.generate_report())
bt.save_backtrader_data(user=&quot;均值方差再平衡&quot;)

9.2 示例2:季度再平衡 + 高分散约束

bt = xg_mean_var_backtrader(
    start_date=&#x27;20230101&#x27;,
    end_date=&#x27;20261201&#x27;,
    stock_list=[&#x27;159915.SZ&#x27;, &#x27;510300.SH&#x27;, &#x27;518880.SH&#x27;, &#x27;511010.SH&#x27;, &#x27;159937.SZ&#x27;],
    cash=500000,
    lookback_days=120,    # 长回看窗口
    interval=63,          # 约每季度(63交易日)调仓
    max_weight=0.3,       # 高分散:上限30%
    min_weight=0.1,       # 每只至少10%
)
bt.run_backtest()
print(bt.get_weight_history().tail())   # 查看最近权重分配
print(bt.generate_report())

9.3 示例3:自定义标的数据注入 + 均值方差回测

import pandas as pd

bt = xg_mean_var_backtrader(
    start_date=&#x27;20230101&#x27;,
    end_date=&#x27;20261201&#x27;,
    stock_list=[&#x27;159915.SZ&#x27;, &#x27;513100.SH&#x27;, &#x27;518880.SH&#x27;],
    cash=1000000,
    max_workers=4,
)

# 注入自定义数据(DataFrame 需含 date/open/high/low/close/volume)
# bt.add_stock_data_from_csv(&#x27;159915.SZ&#x27;, &#x27;data/159915.csv&#x27;)
# bt.add_stock_data_from_excel(&#x27;513100.SH&#x27;, &#x27;data/513100.xlsx&#x27;)
# bt.add_stock_data_from_dataframe(&#x27;159915.SZ&#x27;, pd.read_parquet(&#x27;data/159915.parquet&#x27;))

bt.run_backtest()
bt.save_to_json(&#x27;result/mean_var.json&#x27;)

9.4 示例4:注入自定义指数数据

bt = xg_mean_var_backtrader(
    start_date=&#x27;20230101&#x27;,
    end_date=&#x27;20261201&#x27;,
    stock_list=[&#x27;159915.SZ&#x27;],
    cash=500000,
)

# 构造或读取指数 DataFrame(含 date/close 即可)
import pandas as pd
index_df = pd.read_parquet(&#x27;data/my_index.parquet&#x27;)   # 需 date/close 列
bt.use_custom_index_data = True
bt.add_index_data_from_dataframe(index_df)
print(&quot;是否有指数:&quot;, 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()
weights = bt.get_weight_history()

print(f&quot;总收益率: {metrics[&#x27;total_return&#x27;]*100:.2f}%&quot;)
print(f&quot;年化收益率: {metrics[&#x27;annual_return&#x27;]*100:.2f}%&quot;)
print(f&quot;最大回撤: {metrics[&#x27;max_drawdown&#x27;]*100:.2f}%&quot;)
print(f&quot;夏普比率: {metrics[&#x27;sharpe_ratio&#x27;]:.3f}&quot;)
print(f&quot;胜率: {metrics[&#x27;win_rate&#x27;]*100:.2f}%&quot;)
print(f&quot;交易笔数: {trades[&#x27;statistics&#x27;][&#x27;total_trades&#x27;]}&quot;)

import matplotlib.pyplot as plt
dates = curve[&#x27;dates&#x27;]
fig, axes = plt.subplots(2, 1, figsize=(12, 8), sharex=True)
axes[0].plot(dates, curve[&#x27;net_value&#x27;], label=&#x27;策略净值&#x27;, linewidth=2)
if curve.get(&#x27;benchmark_net_value&#x27;):
    axes[0].plot(dates, curve[&#x27;benchmark_net_value&#x27;], label=&#x27;基准(等权持有)&#x27;, linestyle=&#x27;--&#x27;)
axes[0].legend(); axes[0].set_title(&#x27;组合净值 vs 基准&#x27;)
# 权重面积图
if weights is not None and not weights.empty:
    wd = weights.set_index(&#x27;date&#x27;)
    wd.plot.area(ax=axes[1], alpha=0.6)
    axes[1].set_title(&#x27;最优权重历史(均值方差优化)&#x27;)
plt.xticks(rotation=45); plt.tight_layout(); plt.show()

9.6 示例6:按标的查看再平衡结果与权重分配

bt.run_backtest()

# 各标的独立结果
for stock, res in bt.get_stock_results().items():
    print(f&quot;=== {stock} ===&quot;)
    print(f&quot;  期末资产: {res[&#x27;final_value&#x27;]:.2f}, 持仓: {res[&#x27;final_holdings&#x27;]}份&quot;)

# 最新一期最优权重
weights = bt.get_weight_history()
if weights is not None and not weights.empty:
    last_row = weights.iloc[-1]
    print(&quot;\n最近一次最优权重分配:&quot;)
    for stock in bt.stock_list:
        print(f&quot;  {stock}: {last_row[stock]*100:.1f}%&quot;)

# 年度绩效
print(&quot;\n&quot;, 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_* 只需 date+close(自动剔除 close≤0、识别日期列);注入后 use_custom_index_data=True 时优先作为指数基准。

10.3 注入成功判定与验证

print(&quot;标的自定义键:&quot;, bt.get_custom_data_keys())   # 含代码即成功
print(&quot;has_custom_data:&quot;, bt.has_custom_data(&#x27;159915.SZ&#x27;))
print(&quot;指数:&quot;, bt.has_index_data(), bt.get_index_data_info())

十一、常见问题与 FAQ

Q1: 提示「没有共同的交易日期」或回测终止?

align_data 需要全部标的共同交易日交集非空。检查各标的数据日期范围是否重叠足够;缺某标的长期停牌/无数据会显著压缩回测区间。

Q2: 为什么交易次数很少或某只总不交易?

再平衡仅在 interval 个交易日且 |diff|≥总资产×0.5% 时触发;若当前权重已贴近目标权重(尤其等权优化结果),差异小于死区则不交易,属正常。可调小 interval 或死区逻辑(代码内 0.005)。

Q3: 权重始终是等权,没有优化效果?

可能原因:数据总行数 ≤ lookback_days+30(calculate_optimal_weights_ts 内 len&lt;30 恒退回等权);或 SLSQP 求解失败。增大历史数据 / 检查数据质量。

Q4: 如何理解 lambda_risk 参数?

当前版本 lambda_risk 仅存储与打印,目标函数是最大化夏普比率(negative_sharpe),未用 return − lambda×risk 形式。想启用风险厌恶形式可继承重写 optimize_max_sharpe。

Q5: 自定义数据注入后仍走本地目录?

确认注入返回 True,用 get_custom_data_keys() 验证,并把 use_custom_data=True(或确认注入方法自动切换)。

Q6: 收益率为 0 或异常?

检查价格列是否全为正、cash 初始值、stock_list 是否都有数据、成交撮合是否因手续费过高导致 actual_cost&gt;amount 而 0 份、以及是否因 zdf 缺失导致收益矩阵全 NaN。

Q7: 单标的权重会超 max_weight 吗?

优化层有 bounds 约束,SLSQP 结果理论上不超 max_weight。但因价格跳动与整数手撮合,实际持仓权重会略偏离目标,需靠下个再平衡周期拉回。

Q8: 某标的首日无价格 / 建仓失败?

initial_weights 等权下若首日该标无有效价格则跳过建仓;若全部标的都无法建仓,回测结果将只剩现金。确认首日各标的有行情。

十二、高级技巧与二次开发

12.1 参数调优建议

参数 建议范围 说明
lookback_days 30-250 越长估计越稳但对市场变化越滞后;过短(<30)恒退回等权
interval 5-63 越小调仓越频繁、手续费越高;63≈季度再平衡
max_weight 0.2-0.6 越小越分散;取决于资产池相关性与集中度偏好
min_weight 0.02-0.1 下限越高越强制分散
cash / 资产池 3-6 只 太少无法体现分散优势,太多约束过紧难优化

12.2 均值方差策略设计经验

  • 资产低相关是前提:均值方差的核心收益来自低相关资产搭配,尽量混入股/债/商品/黄金等不同风险资产。
  • 收益/协方差估计:zdf 均值×252 与协方差×252 是朴素年化估计,实盘可用更长窗口或收缩估计(可在 get_returns_matrix 扩展)。
  • 再平衡纪律:死区与 interval 缺一不可,避免过度交易吞噬收益。

12.3 自定义优化目标(风险厌恶/效用最大化)

继承 xg_mean_var_backtrader,重写 optimize_max_sharpe 引入 lambda_risk:

from scipy.optimize import minimize
import numpy as np

class MyMeanVar(xg_mean_var_backtrader):
    def negative_utility(self, w, mu, cov, lam):
        ret = np.dot(w, mu)
        vol = np.sqrt(np.dot(w.T, np.dot(cov, w)))
        return -(ret - 0.5 * lam * vol ** 2)   # 均值-方差效用(负)
    def optimize_max_sharpe(self, returns_df):
        n = len(returns_df.columns)
        mu = returns_df.mean() * 252
        cov = returns_df.cov() * 252
        cons = [{&#x27;type&#x27;: &#x27;eq&#x27;, &#x27;fun&#x27;: lambda x: np.sum(x) - 1}]
        bnds = tuple((self.min_weight, self.max_weight) for _ in range(n))
        res = minimize(self.negative_utility, np.array([1/n]*n),
                       args=(mu, cov, self.lambda_risk),
                       method=&#x27;SLSQP&#x27;, bounds=bnds, constraints=cons)
        w = res.x if res.success else np.array([1/n]*n)
        return np.maximum(w, 0) / np.maximum(np.sum(np.maximum(w, 0)), 1e-12), mu, cov

12.4 自定义交易/成本规则

重写 calculate_buy_shares(改买入逻辑)、calculate_sell_shares_by_value(改卖出逻辑)、或 calculate_performance_metrics(加自定义绩效指标)。

十三、技术说明与提示

  • 单一整体资金池:cash 不均分到各标的,全仓按权重分配,累计收益率按总初始资金 cash 折算。
  • 依赖 scipy:均值方差优化需 scipy(minimize/stats),安装时务必带上。
  • 无模块级函数:全部逻辑在类内,63 个方法覆盖对齐/优化/撮合/绩效全流程。
  • 权重约束口径:min_weight/max_weight 作用于优化目标权重;实际因整数手撮合略有偏离。
  • 指数数据仅用于输出留档,策略对照基准为「等权持有不动」曲线(calculate_benchmark_curve)。
  • 交易类型仅 初始建仓 / 再平衡买入 / 再平衡卖出,无做T/止损/信号概念。
  • 源码当前固定 adj_type=&#x27;none&#x27;,若需复权需二次开发 _normalize_dataframe。

小果均值方差回测系统,让现代组合理论落地更高效、更透明。如需源码、更多因子库或技术支持,欢迎联系小果(微信:xg_quant)。

常见问题

5 问
答案由本站依据条目字段整理
小果均值方差回测系统助手怎么安装?

在支持 Skills 的客户端里执行:skillhub install user_676c825d/xg-mean-var-backtrader。安装方式为未标注。装完刷新技能列表或重开客户端。

小果均值方差回测系统助手支持哪些客户端?

资料没有标注宿主客户端,但只要客户端支持 Skills(Claude、Codex、Cursor 等),一般都能加载。

小果均值方差回测系统助手权限高吗,安全吗?

权限级别为未标注权限。安装前先看它会读取或写入哪些内容。

小果均值方差回测系统助手收费吗?

本站不代收费用,也没有标注具体价格。是否收费取决于技能本身和所用的模型或客户端,正式使用前按作者说明确认。

小果均值方差回测系统助手用什么许可证?

许可证标注为 未说明(许可证不明确)。商用或二次分发前请到仓库确认条款原文。

热门专题

按场景挑技能
全部专题 →

技能内容以作者仓库为准;分类、权限级别与许可证状态的中文说明为中文整理,最近核验 2026-11-06。