用 Zorro 做策略回测,需要 T6 格式的历史数据。Zorro 自带的数据源有限,我常用的几个标的(SPY、VIX、HYG 等)不在其中,只能自己动手准备。
我的需求很简单:获取美股日线数据,转成 Zorro 能用的格式。
数据源选择 Yahoo Finance,免费且覆盖面广,虽然数据质量不算高,但用来验证策略原型已经足够。
整个流程分两步:
- 用 Python 下载历史数据,保存为本地 CSV 文件。
- 用 lite-C 脚本把 CSV 转成 T6 历史文件。
第一步:Python 下载数据
用 yfinance 库下载,保存调整后的 OHLCV 数据。完整脚本如下:
python
"""
从 yahoo finance 下载美股日历史数据。
将调整 ohlcv 保存到指定本地目录。
"""
import os
import time
import warnings
import yfinance as yf
import pandas as pd
warnings.filterwarnings("ignore")
# ==================== 参数配置 ====================
TICKERS = ["SPY", "^VIX", "^VIX3M", "HYG", "IEF"] # 股票代码
START_DATE = "2000-01-01" # 格式: YYYY-MM-DD
END_DATE = "" # "" 表示最新
OUTPUT_DIR = "Log" # 输出目录(相对目录,默认根目录是zorro主目录)
PROXY_ENABLED = False # 是否使用代理
PROXY_HOST = "127.0.0.1" # 主机地址
PROXY_PORT = 7890 # 代理端口
# =================================================
def fetch(ticker: str) -> pd.DataFrame:
if PROXY_ENABLED:
yf.config.network.proxy = f"http://{PROXY_HOST}:{PROXY_PORT}"
df = yf.download(
ticker,
start=START_DATE,
end=END_DATE or None,
interval="1d",
auto_adjust=True, # 仅输出调整后 ohlcv
progress=False,
threads=False,
multi_level_index=False,
)
return df
def save_csv(out_dir: str, ticker: str, df: pd.DataFrame) -> str:
# 部分股票代码包含前缀"^",删除,确保存储格式一致
filename = ticker.lstrip("^")
path = os.path.join(out_dir, f"{filename}.csv")
df = df[["Open", "High", "Low", "Close", "Volume"]]
df.index = df.index.tz_localize(None)
df.to_csv(path, header=True, float_format="%.4f", date_format="%Y-%m-%d")
return path
def main():
root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
out_dir = os.path.join(root, OUTPUT_DIR)
if not os.path.isdir(out_dir):
os.makedirs(out_dir)
for ticker in TICKERS:
print(f"Downloading {ticker} ...")
try:
df = fetch(ticker)
except Exception as e:
print(f" FAILED: {e}")
continue
path = save_csv(out_dir, ticker, df)
print(f" SUCCESS: {len(df)} bars -> {path}")
if len(TICKERS) > 1:
time.sleep(1) # 限制请求
if __name__ == "__main__":
main()
要点说明:
auto_adjust=True:输出复权后的价格,省去自己处理分红拆股。- 文件名处理:指数代码带
^前缀(如^VIX),保存时去掉,保证文件名统一。 - 请求间隔:多个标的循环下载时,每次停顿 1 秒,避免请求过快。

第二步:Zorro 转换为 T6
CSV 不是 Zorro 的原生格式,回测前要转成 T6 历史文件,需要创建 lite-c 脚本,脚本如下:
c
// 将 yahoo finance 日历史数据转化为 t6 历史文件
// csv 行字段格式,dataParse 函数按照指定格式解析行数据
// +:csv 按升序排列,解析后的历史文件按降序排列
// %Y-%m-%d:日期格式
// f3:开盘价;f1:最高价;f2:最低价;f4:收盘价;f6:成交量
// 默认跳过表头行
// csv 示例:
// Date,Open,High,Low,Close,Volume
// 2000-01-03,92.6650,92.6650,89.9304,90.9070,8164300
// 2000-01-04,89.7155,90.0476,87.2837,87.3520,8089800
string Format = "+%Y-%m-%d,f3,f1,f2,f4,f6";
// 要转换的资产id,用逗号分隔
string Symbols = "SPY,VIX,VIX3M,HYG,IEF";
// csv 文件目录(相对目录)
string InputDir = "Log";
// t6 历史文件目录
string OutputDir = "History";
function main()
{
int n = 0;
string Symbol = strtok(Symbols, ",");
while(Symbol) {
printf("\n[%d] Process %s", ++n, Symbol);
string InputPath = strf("%s\\%s.csv", InputDir, Symbol);
string OutputPath = strf("%s\\%s.t6", OutputDir, Symbol);
if(!file_date(InputPath)) {
printf("\n[%d] File not found: %s", InputPath);
Symbol = strtok(0, ",");
continue;
}
dataNew(1, 0, 0);
int Records = dataParse(1, Format, InputPath);
if(!Records) {
printf("\n[%d] Failed to parse csv!", n);
Symbol = strtok(0, ",");
continue;
}
printf("\n[%d] Loaded %d lines", n, Records);
dataSave(1, OutputPath);
printf("\n[%d] Save to %s", n, OutputPath);
Symbol = strtok(0, ",");
}
}
核心逻辑是调用dataParse和dataSave函数,Format 字符串定义了 CSV 的解析规则:
+:CSV 按日期升序排列,转换后按降序存储,这是 zorro 要求的。%Y-%m-%d:日期格式。f3,f1,f2,f4,f6:分别是开盘,最高,最低,收盘,成交量,对应 CSV 的列位置。- 表头行默认跳过,不用额外处理。
脚本会遍历 Symbols 里的每个标的,找到对应 CSV,解析后保存到 History 目录。

使用步骤
- 把 Python 脚本放到 Zorro 主目录下的子目录里,运行它,生成 CSV 文件(自己管理 python 环境)。
- 把 Zorro 脚本放入 Zorro 主目录,编译并运行。
- 到
History目录确认 T6 文件是否生成。
注意事项
- CSV 文件名必须和
Symbols里的名称一致。比如^VIX下载后存为VIX.csv,Symbols里就写VIX。 - 如果某个 CSV 缺失或解析失败,脚本会跳过它,继续处理下一个,不会中断。
- 目录路径是相对 Zorro 主目录的。如果放别处,改
InputDir和OUTPUT_DIR即可。
小结
处理流程包含两步:Python 负责下载,Zorro 负责转换。数据质量虽一般,但足够验证策略原型。原型验证通过后,再换更高质量的数据源进行深度测试和优化。