产物与落盘¶
Visualizer 把 AnalysisResult 渲染成 PNG 与 CSV,并返回落盘文件清单。图与表平铺在同一层,不分子目录。
不落盘也能取用全部结果¶
交互式分析时产物不必先写到磁盘。BacktestResult 保留了每一层的中间产物:
bt = alp.backtest(signals=alpha_df, prices=price_df, horizon=5)
bt.summary() # 指标表
bt.returns # 逐期组合收益长表
bt.curves # 净值与累计对数收益曲线
bt.ic, bt.turnover # 诊断序列
bt.members # 逐期分桶成分明细
bt.aligned # alpha × 前视收益 × 市值 的对齐面板
要落盘时再调 save(),见下文。
落盘位置¶
output_dir |
走 run_pipeline / save() |
单独用 Visualizer(cfg) |
|---|---|---|
| 留空,输入是文件 | 落到首路信号文件同级的 outputs/ |
抛 ContractError |
| 留空,输入是内存 DataFrame | 抛 ContractError |
抛 ContractError |
| 显式给出 | 按给出的路径 | 按给出的路径 |
输入为文件时留空是推荐做法:产物与数据放在一起,不随进程当前工作目录漂移。
内存 DataFrame 没有数据文件可作落点锚,因此必须显式给出目录——不猜测落点,也不悄悄写进当前 工作目录:
<信号文件所在目录>/
├── alpha1.feather
├── alpha2.feather
└── outputs/ ← 自动创建
├── long_short_ew.png
├── long_short_vw.png
├── deciles_alpha1_ew.png
├── deciles_alpha2_ew.png
├── metrics_by_bucket.csv
├── summary_metrics.csv
└── curves.feather
锚点选信号文件而非价格面板,因为价格面板通常是多个项目共用的只读数据,不该往里写产物。
相对路径按进程当前工作目录解析
显式给出 output_dir 时,相对路径不按配置文件所在目录解析。从不同目录启动会让产物漂移到不同位置。
因此建议要么留空使用默认锚点,要么写绝对路径。该字段支持 ${VAR} 展开。
单独使用 Visualizer(cfg) 时没有信号路径可作锚点,此时必须显式给出 output_dir,否则报错——不会悄悄写入当前目录。
图表¶
每个图表配置 × 每个加权方案产出一张 PNG。save() 默认用 long_short 与 deciles 两个预设,
也可以只要其中之一:
文件名规则:
weight 取加权方案标签的小写形式(EW → ew)。信号名转小写并把非字母数字压成连字符。
拆分规则由 color_mode 自动决定:分位图的色阶正是按分位铺开的,多路信号叠在一起既撞色又撞图例,
因此逐信号拆图;策略对比图恰恰相反,多路信号必须同图才谈得上比较。该行为可由
charts[].split_by_signal 显式覆盖。
图表数量:
weights 留空时取分析结果中出现的全部加权方案。分析结果中一个都没有时抛 ContractError。
数据表¶
每个 tables[] 条目产出一份 CSV,文件名为 {tables[].name}.csv。内置三种类型:
指标汇总表,每行一个 (signal_model, bucket, weight)。
percent_columns 会改列名¶
summary 表中列在 percent_columns 里的字段会乘以 100 并改名为 {列名}_pct,原列删除:
| 配置前的列 | CSV 中的列 | 取值 |
|---|---|---|
ann_ret |
ann_ret_pct |
9.2(而非 0.092) |
max_drawdown |
max_drawdown_pct |
-42.0 |
不在该列表中的指标(如 sharpe、total_equity、ic_mean)保持原始小数。所有数值列按 decimals 四舍五入,但仍保持数值型,便于下游再加工。
需要原始小数时看 summary_metrics.csv
export_returns 导出的 summary_metrics.csv 是未经百分比换算与舍入的完整表。tables[] 产出的是给人看的版本,两者用途不同。
过滤¶
三个字段依次过滤,留空表示不过滤:
{
"name": "hl_only",
"type": "summary",
"buckets": ["H-L", "REF"],
"weights": ["EW"],
"signals": ["alpha1"]
}
完整长表导出¶
export_returns 默认打开,额外落两份未经加工的原始产物:
| 文件 | 内容 |
|---|---|
summary_metrics.csv |
完整指标长表,无百分比换算、无舍入 |
curves.feather |
完整曲线长表 |
curves.feather 的列:
| date | signal_model | bucket | weight | ret | equity | cum_log_ret |
|---|---|---|---|---|---|---|
每条曲线前置一个零点(equity = 1.0、cum_log_ret = 0.0),横坐标为最早一期的前一个工作日。
Python 侧的产物¶
两条入口的返回对象携带同样的中间产物,只是取用方式不同:
| 字段 | 内容 |
|---|---|
bt.returns / bt.curves / bt.ic / bt.turnover |
直接是 DataFrame |
bt.members / bt.aligned |
分桶成分、对齐面板 |
bt.summary(bucket=..., weight=...) |
指标表,带过滤 |
bt.bundle / bt.engine / bt.analysis |
三份原始契约产物 |
bt.config |
本次实验的完整 PipelineConfig |
bt.returns 等属性只是 bt.engine.returns 的转发,两者是同一个对象。
长表结构¶
组合收益采用长表,因此任意数量的加权方案都能装进同一张表,新增方案不改变表结构:
| date | signal_model | bucket | weight | ret | count |
|---|---|---|---|---|---|
bucket 取 "0".."n-1",多空为 "H-L",外部基准为 "REF"。
转回宽表¶
若下游代码需要 anchor_date / decile / ew_ret / vw_ret 这类宽表列名:
该函数沿用旧项目的列名,不跟随包内改名。
导出为配置目录¶
to_config() 把一次实验的完整参数导成四份 JSON,供 run_pipeline 复跑或随论文归档:
bt.to_config("paper/configs/", data_dir="paper/data/")
result = alp.run_pipeline("paper/configs/") # 复现
内存 DataFrame 写不进 JSON,因此内存输入时需给出 data_dir:表先落盘到该目录,再把路径写进
配置。复现包本就需要数据随行,这一步是该场景的固有要求而非额外负担。
导出的配置包含 save() 用的图表与数据表预设,因此复跑时产物与原来一致。
命令行的输出¶
默认打印输入摘要(JSON)与 headline 指标(只含 H-L 与 REF 行),然后逐行列出落盘文件:
两个开关:
| 参数 | 作用 |
|---|---|
--no-render |
只算不出图,不产出任何文件 |
--quiet |
不打印摘要与指标,仅列出落盘文件 |