🚀 AI 一键生成 joinquant 策略代码
立即体验
👉 AI 生成代码 👈

JoinQuant聚宽平台如何读取研究环境文件?(解决open函数“No such file”报错)

joinquant | 发布时间: 2026/6/2
以下内容由 EasyQuant 生成。

问题描述

open函数在回测和模拟环境中如何读取研究中的文本文件?

聚宽的read_file函数不够用,open 函数 总是报“No such file or、、、”。哪里出了问题呢?

解决方案

为什么在回测/模拟环境中使用 open 函数会报错?

在 JoinQuant(聚宽)平台上,研究环境回测/模拟交易环境在底层是相互隔离的沙盒环境。当您在研究环境(Jupyter Notebook)中看到的文件,其相对路径在回测引擎中并不适用。因此,如果您直接在回测代码中使用 Python 原生的 open('filename.txt'),系统会因为在回测沙盒的当前工作目录下找不到该文件,从而抛出 No such file or directory 的错误。

此外,聚宽官方文档在“模拟盘注意事项”中也明确指出:涉及到 IO(如打开的文件 open("some/path"))的对象是不能被序列化的,直接使用 open 可能会导致模拟盘在每日休眠和重启保存状态时发生崩溃。

为什么觉得 read_file “不够用”?

很多开发者觉得 read_file 不够用,通常是因为第三方库(如 pandas.read_csvjson.load)需要传入一个文件对象(File-like object),而聚宽的 read_file(path) 返回的是文件的原始内容(字符串或字节流)。直接将字符串传给需要文件对象的函数自然会报错。

完美的解决方案:read_file + StringIO / BytesIO

要解决这个问题,您不需要(也不能)使用 open 函数。正确的做法是:使用 read_file 获取内容后,利用 Python 内置的 io 模块将其转换为内存中的文件对象。这样既符合聚宽的 API 规范,又能完美兼容所有需要文件对象的第三方库。

场景一:读取 CSV 文件并使用 Pandas 解析

如果您需要用 pandas 读取研究环境中的 CSV 文件,可以结合 BytesIO(Python 3 环境)或 StringIO(Python 2 环境)来实现:

# Python 3 环境下的标准写法(推荐)
import pandas as pd
from six import BytesIO

def initialize(context):
    # 1. 使用 read_file 读取文件原始字节流
    body = read_file("my_data.csv")
    
    # 2. 使用 BytesIO 将字节流包装成文件对象,传给 pandas
    df = pd.read_csv(BytesIO(body))
    
    log.info("成功读取数据,前5行为:\n%s" % df.head())

场景二:读取 JSON 配置文件

如果您在研究环境中保存了股票池或参数配置的 JSON 文件,可以直接使用 json.loads 解析 read_file 返回的字符串:

import json

def initialize(context):
    # 1. 读取文件内容(返回字符串)
    content = read_file('HS300.stocks.json')
    
    # 2. 直接使用 json.loads 解析字符串
    securities = json.loads(content)
    
    log.info("成功加载股票池,数量:%d" % len(securities))
    g.my_stocks = securities

场景三:按行读取普通文本文件

如果您习惯了 open().readlines() 的操作,可以对 read_file 的结果直接进行字符串分割:

def initialize(context):
    # 读取文本内容
    text_content = read_file('config.txt')
    
    # 按行分割,模拟 readlines() 的效果
    # 注意:如果是 Python 3,read_file 可能返回 bytes,需要先 decode('utf-8')
    if isinstance(text_content, bytes):
        text_content = text_content.decode('utf-8')
        
    lines = text_content.splitlines()
    for line in lines:
        log.info("读取到一行: %s" % line)

总结与注意事项

  1. 绝对不要在回测/模拟中使用 open():路径隔离会导致找不到文件,且文件句柄无法被聚宽系统序列化保存。
  2. 统一使用 read_file(path)path 是相对于您私有空间(研究模块)根目录的相对路径。
  3. 善用内存文件对象:遇到需要传入文件句柄的第三方库,请使用 six.BytesIO(read_file('...'))six.StringIO(read_file('...')) 进行桥接。
  4. 注意 Python 版本差异:聚宽 Python 3 环境下 read_file 通常返回 bytes,处理纯文本时可能需要 .decode('utf-8')