问题描述
解决方案
在 QMT 策略中导入外部文件的股票代码,主要有两种方式:一种是使用 QMT 自带的 API 接口,另一种是使用 Python 原生的文件读取功能(或 Pandas)。
以下是具体的实现方法和代码示例。
方法一:使用 QMT 自带 API (load_stk_list)
QMT 提供了 ContextInfo.load_stk_list 函数,专门用于读取文本文件中的证券代码。
文件格式要求:
假设你的文件 mylist.txt 内容如下(代码之间用逗号分隔):
600000.SH,000001.SZ,600036.SH
策略代码:
# -*- coding: gbk -*-
def init(ContextInfo):
# 1. 定义文件路径和文件名
# 注意:请确保路径存在,Windows路径建议使用反斜杠 / 或双斜杠 \\
file_path = 'D:/QuantData/'
file_name = 'mylist.txt'
try:
# 2. 调用API读取文件内容
# 该函数返回的是文件内的字符串内容
content = ContextInfo.load_stk_list(file_path, file_name)
if content:
# 3. 处理字符串,转换为列表
# 假设文件内容是用逗号分隔的
stock_list = content.split(',')
# 去除可能存在的空白字符
stock_list = [stk.strip() for stk in stock_list if stk.strip()]
# 4. 设置到股票池
ContextInfo.set_universe(stock_list)
print(f"成功导入 {len(stock_list)} 只股票: {stock_list}")
else:
print("文件内容为空或读取失败")
except Exception as e:
print(f"读取文件出错: {e}")
def handlebar(ContextInfo):
# 打印当前运行的股票代码,验证是否在股票池中
# print(ContextInfo.stockcode)
pass
方法二:使用 Python 原生方式(推荐,更灵活)
如果你需要读取 CSV、Excel 或者一行一个代码的 TXT 文件,使用 Python 原生的 open() 或第三方库 pandas 会更加灵活。
场景 A:读取 TXT 文件(一行一个代码)
假设文件 stocks.txt 内容如下:
600000.SH
000001.SZ
600036.SH
策略代码:
# -*- coding: gbk -*-
def init(ContextInfo):
# 定义完整文件路径
full_path = r'D:\QuantData\stocks.txt'
stock_list = []
try:
# 使用原生 Python 读取
with open(full_path, 'r', encoding='utf-8') as f:
# 逐行读取并去除换行符
lines = f.readlines()
stock_list = [line.strip() for line in lines if line.strip()]
# 设置股票池
ContextInfo.set_universe(stock_list)
print(f"成功从TXT导入 {len(stock_list)} 只股票")
except Exception as e:
print(f"读取TXT文件失败: {e}")
def handlebar(ContextInfo):
pass
场景 B:读取 CSV/Excel 文件(使用 Pandas)
假设文件 stocks.csv 有一列名为 code。
策略代码:
# -*- coding: gbk -*-
import pandas as pd
def init(ContextInfo):
csv_path = r'D:\QuantData\stocks.csv'
try:
# 读取 CSV
df = pd.read_csv(csv_path)
# 假设股票代码在 'code' 这一列
if 'code' in df.columns:
stock_list = df['code'].tolist()
# 确保代码格式正确(例如去除空格)
stock_list = [str(code).strip() for code in stock_list]
ContextInfo.set_universe(stock_list)
print(f"成功从CSV导入 {len(stock_list)} 只股票")
else:
print("CSV文件中未找到 'code' 列")
except Exception as e:
print(f"读取CSV文件失败: {e}")
def handlebar(ContextInfo):
pass
注意事项
- 代码格式:QMT 要求股票代码必须包含后缀(如
.SH或.SZ)。如果你的外部文件只有数字(如600000),你需要在代码中通过字符串拼接补全后缀。 - 文件编码:
- 如果外部文件包含中文字符,请注意编码格式(通常是
utf-8或gbk)。在open()函数中可以通过encoding='utf-8'参数指定。
- 如果外部文件包含中文字符,请注意编码格式(通常是
- 路径写法:
- 在 Python 字符串中,反斜杠
\是转义字符。建议在路径字符串前加r(如r'D:\data\file.txt')或者使用正斜杠/(如'D:/data/file.txt')。
- 在 Python 字符串中,反斜杠
- 运行位置:上述逻辑通常写在
init(ContextInfo)函数中,确保策略启动时只执行一次导入操作。
Q&A
Q: 如果我的外部文件里只有数字代码(如 600000),没有后缀怎么办?
A: 你需要在读取后编写简单的逻辑来判断并添加后缀。例如:
processed_list = []
for code in raw_list:
if code.startswith('6'):
processed_list.append(code + '.SH')
else:
processed_list.append(code + '.SZ')
ContextInfo.set_universe(processed_list)
Q: ContextInfo.load_stk_list 和 Python open 有什么区别?
A: load_stk_list 是 QMT 封装的接口,主要用于读取简单的文本内容。Python open 是标准的文件操作方式,通用性更强,可以处理各种复杂格式和编码,推荐在需要处理复杂数据清洗逻辑时使用 Python 原生方式。
Q: 导入的股票池在回测和实盘中都能生效吗?
A: 是的。ContextInfo.set_universe(stock_list) 设置的股票池在回测和实盘模式下均有效。在实盘模式下,handlebar 会根据这些股票的行情驱动运行(如果订阅了行情)。