【量化研究】美股历史数据获取:Yahoo Finance 转 Zorro 回测格式

用 Zorro 做策略回测,需要 T6 格式的历史数据。Zorro 自带的数据源有限,我常用的几个标的(SPY、VIX、HYG 等)不在其中,只能自己动手准备。

我的需求很简单:获取美股日线数据,转成 Zorro 能用的格式。

数据源选择 Yahoo Finance,免费且覆盖面广,虽然数据质量不算高,但用来验证策略原型已经足够。

整个流程分两步:

  1. 用 Python 下载历史数据,保存为本地 CSV 文件。
  2. 用 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 目录。

使用步骤

  1. 把 Python 脚本放到 Zorro 主目录下的子目录里,运行它,生成 CSV 文件(自己管理 python 环境)。
  2. 把 Zorro 脚本放入 Zorro 主目录,编译并运行。
  3. 到 History 目录确认 T6 文件是否生成。

注意事项

  • CSV 文件名必须和 Symbols 里的名称一致。比如 ^VIX 下载后存为 VIX.csv,Symbols 里就写 VIX。
  • 如果某个 CSV 缺失或解析失败,脚本会跳过它,继续处理下一个,不会中断。
  • 目录路径是相对 Zorro 主目录的。如果放别处,改 InputDir 和 OUTPUT_DIR 即可。

小结

处理流程包含两步:Python 负责下载,Zorro 负责转换。数据质量虽一般,但足够验证策略原型。原型验证通过后,再换更高质量的数据源进行深度测试和优化。

相关推荐
小嘉丶学长1 小时前
Day13 · 列表与元组
linux·运维·服务器·开发语言·python
小小张说故事2 小时前
Python 的 int 为什么不会溢出?拆开 PyLongObject 和它背后那串变长数组
python
威哥爱编程2 小时前
Python 智能体开发实战 03:聊十轮就“失忆”,账单还翻倍?管好上下文,Token 立省一半
python·agent
情 九2 小时前
MCP 开发环境搭建:Mac 与 Windows 跑通 Python 服务和 stdio 客户端
windows·python·macos·mcp
SEO_juper2 小时前
Bash 交叉验证 robots.txt 和 sitemap:两个文件自相矛盾,页面永远收录不了
开发语言·python·node.js·json·bash
日日大王学编程2 小时前
LangGraph 基本用法详解:从入门到实战
python·语言模型·langchain
威哥爱编程2 小时前
Python 智能体开发实战 04:模型答得挺漂亮,程序却读不懂?让回答直接变成能入库的 JSON
python·agent
全栈陈序员3 小时前
【Python】基础语法入门(三十)—— Web 开发入门:用 Flask 搭建第一个网站
前端·python·flask
全栈陈序员3 小时前
【Python】基础语法入门(三十三)—— 日志系统详解:用 logging 记录程序运行
java·开发语言·python