🚀 AI 一键生成 qmt 策略代码

如何用 QMT 从 TXT 或 CSV 文件中加载和管理动态股票池?

qmt | 发布时间: 2025/12/8
以下内容由 EasyQuant 生成。

问题描述

我每天都会筛选一批股票保存在一个txt文件里,怎么让策略自动读取这个文件里的股票作为股票池来运行?

解决方案

在 QMT 中,可以通过 Python 标准的文件读取操作(open 函数)或者 QMT 提供的 ContextInfo.load_stk_list 接口来读取本地 TXT 文件,并将读取到的股票代码列表赋值给 ContextInfo.set_universe()

以下是具体的实现方案和代码。

实现思路

  1. 准备 TXT 文件:假设您的文件名为 stocks.txt,内容格式为一行一个股票代码(例如 600000.SH),或者用逗号分隔。
  2. 编写读取函数:在策略中编写一个函数,用于打开指定路径的文件,解析出股票代码列表。
  3. init 中调用:在策略初始化时调用该函数,并将结果传入 ContextInfo.set_universe()

策略代码

# -*- coding: gbk -*-
import os

def init(ContextInfo):
    # ================= 参数设置 =================
    # 请将此处修改为您 txt 文件的实际绝对路径
    # 注意:Windows路径建议使用双反斜杠 \\ 或正斜杠 /
    file_path = 'D:\\quant_data\\stocks.txt' 
    
    # ================= 读取股票池 =================
    stock_list = get_stocks_from_txt(file_path)
    
    if stock_list:
        # 设定股票池
        ContextInfo.set_universe(stock_list)
        print(f"成功从文件读取 {len(stock_list)} 只股票")
        print(f"股票池示例: {stock_list[:5]}") # 打印前5个确认
    else:
        print("警告:未能从文件中读取到股票,请检查路径或文件内容")
        # 如果读取失败,可以设置一个默认列表,防止报错
        ContextInfo.set_universe(['600000.SH'])

    # 设置账号(示例)
    # ContextInfo.set_account('您的资金账号')

def handlebar(ContextInfo):
    # 获取当前设置的股票池
    universe = ContextInfo.get_universe()
    
    # 简单的示例逻辑:遍历股票池打印最新价
    # 注意:实盘中请勿在每一根K线都打印大量日志
    if ContextInfo.is_last_bar():
        for stock in universe:
            # 获取最新收盘价
            data = ContextInfo.get_market_data_ex(
                ['close'], 
                [stock], 
                period='1d', 
                count=1, 
                subscribe=True
            )
            if stock in data and not data[stock].empty:
                price = data[stock].iloc[-1]['close']
                print(f"{stock} 最新价: {price}")

def get_stocks_from_txt(file_path):
    """
    读取txt文件并返回股票代码列表
    兼容格式:
    1. 一行一个代码 (600000.SH \n 000001.SZ)
    2. 逗号分隔 (600000.SH,000001.SZ)
    """
    stock_list = []
    
    if not os.path.exists(file_path):
        print(f"错误:文件不存在 -> {file_path}")
        return []

    try:
        # 尝试使用 gbk 编码读取(Windows常见),如果报错则尝试 utf-8
        try:
            with open(file_path, 'r', encoding='gbk') as f:
                content = f.read()
        except UnicodeDecodeError:
            with open(file_path, 'r', encoding='utf-8') as f:
                content = f.read()
        
        # 处理换行符和逗号,统一替换为逗号后分割
        content = content.replace('\n', ',').replace(' ', '')
        raw_list = content.split(',')
        
        # 过滤空字符串并清理格式
        for code in raw_list:
            clean_code = code.strip()
            if clean_code:
                stock_list.append(clean_code)
                
        return stock_list

    except Exception as e:
        print(f"读取文件发生异常: {e}")
        return []

注意事项

  1. 文件路径

    • 代码中的 file_path 必须是绝对路径(例如 D:\\data\\stocks.txt)。
    • 请确保路径中使用双反斜杠 \\ 或者单正斜杠 /,不要直接使用单反斜杠 \,否则会被 Python 识别为转义字符。
  2. 文件编码

    • 代码中已做了兼容处理(优先尝试 GBK,失败则尝试 UTF-8)。如果您的 txt 文件出现乱码,请确保文件保存为 ANSI (GBK) 或 UTF-8 格式。
  3. 股票代码格式

    • TXT 文件中的股票代码必须包含后缀,例如 600000.SH000001.SZ
    • 如果您的文件里只有数字(如 600000),需要在代码的 get_stocks_from_txt 函数中手动添加后缀补全逻辑。
  4. 运行机制

    • init 函数通常只在策略启动时运行一次。如果您每天更新 txt 文件,需要重启策略或者点击“运行”按钮,策略才会重新读取新的股票池。
    • 如果是盘中实时运行且不想重启,可以在 handlebar 中添加定时逻辑(例如每天 9:25 分)重新调用读取函数并执行 set_universe

Q&A

Q: 如果我的 txt 文件里只有数字代码(如 600000),没有 .SH/.SZ 后缀怎么办?
A: 您需要修改 get_stocks_from_txt 函数中的处理逻辑,根据代码首位数字判断后缀。例如:

# 在 append 之前加入判断
if clean_code.startswith('6'):
    clean_code += '.SH'
elif clean_code.startswith('0') or clean_code.startswith('3'):
    clean_code += '.SZ'
stock_list.append(clean_code)

Q: 策略运行中修改了 txt 文件,策略会自动更新吗?
A: 不会。上述代码是在 init 中读取的,只在策略启动瞬间执行。如果需要在盘中动态更新,需要编写定时任务重新读取,或者手动停止并重新运行策略。

Q: QMT 自带的 ContextInfo.load_stk_list 和这个有什么区别?
A: ContextInfo.load_stk_list 是 QMT 的内置函数,功能类似,但使用 Python 原生的 open 函数灵活性更高,可以更容易地处理换行、空格、编码以及自定义的文件格式。建议使用上述提供的 Python 原生写法。