外观
结果数据与指标
本页定义分析结果的结构。保存、读取和导出操作见报告操作;运行中的对象属性见账户与持仓。
结果结构
运行返回值按模块分组,分析结果为 result["sys_analyser"]。pkl 直接保存该分析字典,没有外层 sys_analyser。禁用分析器时没有分析结果。
| 键 | 说明 |
|---|---|
summary | dict,区间、初始资金、期末权益及绩效摘要 |
portfolio | DataFrame,组合每日结算后记录 |
trades | DataFrame,实际成交;没有成交时可为空且没有列 |
stock_account/stock_positions | stock 账户存在时提供;持仓表可为空且没有列 |
future_account/future_positions | future 账户存在时提供;持仓表可为空且没有列 |
series_positions | 有系列日终归属记录时提供,否则可能不存在 |
benchmark_metadata | dict,有基准时保存来源、名称、期初锚点及计算口径 |
benchmark_portfolio | 配置有效基准时提供,date 索引、unit_net_value 列 |
positions_weight | 持仓内部权重的每日分布统计,不是逐标的目标权重表 |
backtest_settings | dict,framework_version 保存运行时的框架版本,另含常用生效费用、撮合与约束设置摘要,不是完整 config |
strategy_metadata | 提供 extra.report_metadata 时保存的策略元数据 |
dividend_events | 分红到账事件 DataFrame;无事件时可为空 |
yearly_risk_free_rates | 年份到年化利率的字典 |
portfolio_event/pressure_test | 有相关记录或可用压力测试区间时提供 |
账户、组合和持仓按交易日结算后记录,分钟回测也是每日频率。日内有交易但日终空仓是合法结果;这些表不能还原盘中持仓和保证金峰值。需要时在策略中另外记录。
portfolio、账户与真实持仓表使用 date 命名的 DatetimeIndex;series_positions 的 date 索引元素为 Python date。跨表比较日期可用 pd.to_datetime 统一。持仓表一个日期可以有多行,不能假定日期唯一。
组合
portfolio 每交易日一行:
| 列 | 说明 |
|---|---|
total_value/cash/market_value | 元,总权益、可用现金、净市值/名义敞口 |
units | 组合份额 |
unit_net_value/static_unit_net_value | 单位净值、前一结算单位净值 |
daily_pnl/daily_returns | 排除外部出入金后的当日盈亏(元)、单位净值日收益率(小数);保存引擎计算值,HTML/Excel 每日表直接使用 |
margin | 期货账户存在时提供,全部真实合约多空保证金合计,元 |
long_market_value/short_market_value | 期货多头/空头非负名义敞口,元 |
gross_market_value | 期货两方向名义敞口之和,元 |
benchmark_unit_net_value | 有基准时提供的基准净值 |
arithmetic_excess_unit_net_value | 策略单位净值减基准单位净值 |
geometric_excess_unit_net_value | 策略单位净值除以基准单位净值,再减 1 |
纯期货的 market_value 为 long_market_value − short_market_value;净敞口为零不意味着没有持仓或保证金。HTML/Excel 期货仓位占比采用保证金/权益。
成交记录
trades 有成交时以自然成交时间建立 datetime 索引,同时保留 datetime 字符串列。同一时间可有多笔成交。
| 列 | 说明 |
|---|---|
datetime | 字符串 YYYY-MM-DD HH:MM:SS,自然成交时间 |
trading_datetime | 字符串,交易日加钟表时间;夜盘不可按它排列自然先后 |
trading_date | 字符串 YYYY-MM-DD,结算交易日 |
order_book_id/symbol | 实际成交代码、名称;期货是实际月合约 |
series | 来源期货系列;非系列成交为空 |
side | BUY 或 SELL 字符串 |
position_effect | OPEN、CLOSE、CLOSE_TODAY 等动作字符串;结合 side 判断开多/平多/开空/平空 |
last_quantity | 股票股数、基金份数、期货手数 |
last_price | 原始成交价,保留完整浮点数值 |
contract_multiplier | 合约乘数;股票基金为 1 |
commission/tax/transaction_cost | 元,佣金、税、该笔交易总费用 |
order_id/exec_id | 订单与成交标识;系统成交可能没有关联订单 |
trade_source | strategy 为策略成交,roll 为期货移仓,expiry 为期货到期清仓;分红再投资等系统成交使用各自来源值 |
成交金额用 last_price × last_quantity × contract_multiplier,不是保证金。trades 不保存全部拒单尝试;拒单看日志或策略自己的订单记录。强平清空账户不必产生对应的逐笔成交,不能仅以成交表推断所有账户变化。
股票基金账户与持仓
stock_account 每交易日一行:cash、market_value、total_value、transaction_cost,单位元。transaction_cost 是当日交易费用,累计须求和。
stock_positions 每日期、代码一行:order_book_id、symbol、quantity、last_price、avg_price、market_value。数量为股/份;价格及平均成本为该日持仓口径,市值为元。基金也在此表,没有独立 fund_positions。
应收分红及公司行为可能影响权益,不能用可用现金加表中市值替代账户 total_value。分红到账明细在 dividend_events,按具体事件读取,不重复加到交易收益。
期货账户与持仓
future_account 每交易日一行,金额单位均为元:
| 列 | 说明 |
|---|---|
cash/total_value | 可用现金、总权益 |
margin | 真实合约多空保证金总和 |
market_value | 带方向的净名义敞口 |
transaction_cost | 当日交易费用,包含策略与系统移仓费用 |
position_pnl | 昨仓从前结算价到当日估值/结算价的盈亏 |
trading_pnl | 当日成交相对当日估值/结算价的盈亏 |
daily_pnl | 当前权益减日初权益再减净外部入金,包含已入账税费及结算费用;常规无额外税费情形下等于上述两类盈亏减交易费用 |
future_positions 每日期、真实合约一行,两个方向放在同一行:
| 列 | 说明 |
|---|---|
order_book_id/symbol | 实际合约代码、名称 |
contract_multiplier/last_price | 乘数、结算后估值价 |
margin | 该合约 LONG_margin 与 SHORT_margin 的合计 |
LONG_quantity/SHORT_quantity | 各方向非负手数 |
LONG_margin/SHORT_margin | 各方向保证金,元 |
LONG_market_value/SHORT_market_value | 各方向非负名义敞口,元 |
LONG_avg_open_price/SHORT_avg_open_price | 结算后成本;名称含 open,但成本会每日重置,不是最初入场价 |
LONG_pnl/SHORT_pnl | 当前估值相对当前成本的未结算盈亏,结算重置后通常为零 |
不存在的方向可能没有对应列或为 NaN;按有持仓的方向读取。margin 应与该行现有两方向保证金之和一致,同一天全部合约合计应与 future_account.margin 对应;已保存数值存在舍入精度。
series_positions 每日期、系列、真实合约、方向一行:series、order_book_id、direction(LONG/SHORT)、quantity(手)、avg_open_price(归属开仓成本)。它不保存一套独立资金或累计收益,不能与 future_positions 重复相加。归属成本与真实合约成本的区别见系列持仓。
读取末日持仓
先处理不存在或空表,再筛选末日;不能取“最后一条持仓记录”充当末日持仓,因为末日可能空仓。
python
import pandas as pd
last_date = pd.Timestamp(analyser["summary"]["end_date"])
positions = analyser["future_positions"]
if positions.empty:
final_positions = positions
else:
final_positions = positions.loc[pd.to_datetime(positions.index) == last_date]
print(final_positions)指标口径
summary 中的常用字段:
| 字段 | 说明 |
|---|---|
start_date/end_date/inception_date | 实际区间、期初基准日期 |
strategy_name/starting_cash | 策略名、初始现金配置说明 |
initial_total_value | 策略开始前的初始总权益,包含初始持仓,不包含后续出入金 |
total_value/cash/unit_net_value | 期末权益、可用现金、单位净值 |
total_returns/annualized_returns | 总收益、年化收益,小数比例 |
max_drawdown | 最大回撤正幅度,如 0.2 表示 20% |
sharpe/sortino/volatility | 夏普、索提诺、年化波动率 |
win_rate/profit_loss_rate | 盈利日比例、盈利日平均盈亏与亏损日平均盈亏绝对值之比,不是逐笔交易指标 |
benchmark_total_returns/benchmark_annualized_returns | 配置基准时的基准收益 |
excess_returns/excess_annual_returns | 几何超额收益及其年化 |
excess_cum_returns | 算术累计超额收益 |
max_drawdown_duration_start_date/end_date/days | 最长回撤持续期起止与自然日数,不是最大回撤峰谷区间 |
绩效直接读取 summary,不从保存后已舍入的净值重算。日度金额和持仓字段通常保留 4 位小数,组合 unit_net_value 保留 6 位;trades.last_price 不按这个规则舍入。展示格式不改变引擎核算。
单位净值期初为 1,首日盈亏与期初高水位计入统计。月、年收益从上一期间末日净值起算,首期从期初起算。报告曲线在首个回测交易日前一交易日绘制净值 1、回撤 0 的锚点,仅供展示,不由首次成交或调仓日期决定。回测日历缺少该日期时运行报错;外部净值也按同一锚点归一化,详见基准与期初净值。
summary.max_drawdown 为正,图中回撤和年度回撤采用负值。每日费用要累计求和,不能取末日 transaction_cost 当作全程费用。期货换手率未按股票市值公式计算,相关指标可为空;保证金使用率与名义杠杆也不是同一指标。
最大回撤区间表示峰值到谷底;最长回撤持续期表示最近高水位到首次恢复该高水位的日期,恰好相等也算恢复。尚未恢复时取末日,按自然日差选择最长区间;全程无回撤时起止均为期初日、天数为 0。两类日期均纳入期初净值 1,超额回撤使用同样规则。
股票基金的区间换手率 turnover 为双边成交金额合计除以区间日均持仓市值,再除以 2;年度表用对应年份的同一公式。annualized_twoside_turnover 再乘 2 和年化天数、除以样本交易日数。期货不计算这类换手率。年度超额收益采用 (1 + 策略收益) / (1 + 基准收益) - 1,与总体几何超额一致。
报告的单标的最高占比采用日终市值/权益;期货采用同一真实合约多空保证金合计/权益。平均持仓天数按真实合约与方向对成交做先进先出配对,并将期末未平仓计算至末日,按数量加权、单位为回测交易日;期货移仓会结束旧合约并开启新合约持有期,不表示连续策略的完整持有期。
日收益指标默认每年 252 个交易日,通过 base.custom_trading_days_a_year 指定其他年化天数。生效值保存在 backtest_settings.trading_days_a_year,摘要、年度表和滚动指标统一读取同一口径;HTML 的指标提示、滚动图说明和回测设置显示实际使用的天数。报告要求结果提供该字段,不自行回退到默认值。
年度表的 volatility 为该年度样本的年化波动率,与顶部和滚动图的波动率含义一致。月度、年度收益仍是所覆盖期间的实际收益,不因年份不完整而放大成年化收益。不同统计区间的夏普和年化波动率可以不同;年化口径统一不意味着所有区间的指标数值相同。
滚动窗口固定为 126 个交易日,与年化天数是两个独立设置。基于周收益和月收益计算的风险指标分别按每年 52 周、12 个月年化;分钟回测的这些绩效仍以每日账户收益计算,不按分钟数量折算。无风险利率的加载和指标开关见数据加载,年度指标使用分年利率;未定义指标保持空值,不补成零。