本文将详细解析一个实用的量化交易工具——将QMT持仓数据导入通达信自定义板块的Python程序。该工具能够自动获取QMT交易系统中的持仓股票,并将其转换为通达信软件可识别的板块文件格式。 程序概述 这个Python脚本主要实现以下功能: - 1. 通过图形界面获取用户配置信息
- 2. 连接QMT交易系统获取持仓数据
- 3. 将持仓股票转换为通达信格式
- 4. 生成通达信自定义板块文件
代码结构解析 def setup_logger():
# 创建logs目录
if not os.path.exists('logs'):
os.makedirs('logs')
# 配置日志文件名(使用日期)
log_file = os.path.join('logs', f'qmt_import_{datetime.now().strftime("%Y%m%d")}.log')
# 创建日志记录器
logger = logging.getLogger('QMTImport')
logger.setLevel(logging.INFO)
# 创建文件处理器(限制单个文件大小为5MB,最多保留5个文件)
file_handler = RotatingFileHandler(log_file, maxBytes=5*1024*1024, backupCount=5, encoding='utf-8')
file_handler.setLevel(logging.INFO)这段代码配置了一个完善的日志系统:
• 自动创建logs目录存储日志文件 • 按日期生成日志文件名 • 使用RotatingFileHandler实现日志轮转,防止单个日志文件过大 • 同时输出到文件和终端控制台 class ConfigGUI:
def __init__(self):
self.root = tk.Tk()
self.root.title("仓鼠智能交易系统--QMT持仓导入通达信")
self.root.geometry("800x600")
# 默认配置
self.qmt_path = tk.StringVar(value=r"D:\通达信\国金QMT交易端模拟\userdata_mini")
self.tdx_path = tk.StringVar(value=r"D:\通达信\自用版")GUI类使用tkinter库创建,主要特点包括:
• 设置默认路径,方便用户直接使用 • 提供浏览按钮选择目录 • 包含日志显示区域,实时反馈操作结果 • 输入验证功能,确保必要参数已填写 def connect_qmt():
try:
# 生成会话ID
session_id = int(time.time()) % 1000000
# 创建交易对象
xt_trader = XtQuantTrader(QMT_PATH, session_id)
xt_trader.start()
# 连接交易服务器
if xt_trader.connect() != 0:
log_message("错误: 连接QMT交易服务器失败")
return None连接QMT的核心步骤: - 1. 生成唯一的会话ID
- 2. 创建XtQuantTrader交易对象
- 3. 启动交易连接
- 4. 订阅指定账户
- 5. 持仓数据获取
def get_positions(xt_trader):
account = StockAccount(QMT_ACCOUNT)
positions = xt_trader.query_stock_positions(account)
# 获取股票名称和最新价格
stock_info = get_stock_info(stock_codes)
# 计算盈亏百分比
profit_percent = (price / cost - 1) * 100获取持仓数据后,程序还会:
• 查询股票的实时行情数据 • 计算每只股票的盈亏比例 • 格式化输出持仓明细 def export_to_tdx(positions):
# 转换代码格式为通达信格式
if code.endswith('.SH'):
tdx_code = '1' + code.split('.')[0]
elif code.endswith('.SZ'):
tdx_code = '0' + code.split('.')[0]
# 写入板块文件
with open(block_file, 'w', encoding='gbk') as f:
f.write('\n'.join(stock_codes))代码转换规则:
• 上海市场股票:前缀1+股票代码 • 深圳市场股票:前缀0+股票代码 • 使用GBK编码写入文件,确保通达信能正确识别 技术要点总结 - 1. 多线程安全:通过生成唯一会话ID确保多实例运行安全
- 2. 错误处理:完善的异常捕获和日志记录机制
- 3. 性能优化:批量获取股票行情数据,减少API调用次数
- 4. 兼容性:处理不同市场股票代码的转换规则
- 5. 用户体验:图形界面与日志反馈相结合
实际应用价值 该工具解决了量化交易中的一个常见需求:将QMT系统中的持仓股票快速导入到通达信软件中进行分析。主要优势包括: - 1. 自动化:无需手动记录和输入股票代码
- 2. 实时性:获取最新持仓和行情数据
- 3. 可视化:直观显示盈亏情况
- 4. 灵活性:可自定义板块名称和存储路径
对于同时使用QMT和通达信的投资者,这个工具能显著提高工作效率,实现两个平台之间的数据无缝衔接。 - #!/usr/bin/env python
- # -*- coding: utf-8 -*-
- from __future__ import print_function
- import os
- import sys
- import json
- import uuid
- import shutil
- import platform
- import re
- from datetime import datetime
- import errno
- def get_storage_path():
- """获取配置文件路径"""
- system = platform.system().lower()
- home = os.path.expanduser('~')
-
- if system == 'windows':
- return os.path.join(os.getenv('APPDATA'), 'Cursor', 'User', 'globalStorage', 'storage.json')
- elif system == 'darwin': # macOS
- return os.path.join(home, 'Library', 'Application Support', 'Cursor', 'User', 'globalStorage', 'storage.json')
- else: # Linux
- return os.path.join(home, '.config', 'Cursor', 'User', 'globalStorage', 'storage.json')
- def get_main_js_path():
- """获取main.js文件路径"""
- system = platform.system().lower()
-
- if system == 'darwin': # macOS
- return '/Applications/Cursor.app/Contents/Resources/app/out/main.js'
- elif system == 'windows': # Windows
- user_profile = os.getenv('LOCALAPPDATA') # 使用LOCALAPPDATA而不是USERPROFILE
- if not user_profile:
- return None
- return os.path.join(user_profile, 'Programs', 'cursor', 'resources', 'app', 'out', 'main.js')
- return None
- def generate_random_id():
- """生成随机ID (64位十六进制)"""
- return uuid.uuid4().hex + uuid.uuid4().hex
- def generate_uuid():
- """生成UUID"""
- return str(uuid.uuid4())
- def backup_file(file_path):
- """创建文件备份"""
- if os.path.exists(file_path):
- backup_path = '{}.backup_{}'.format(
- file_path,
- datetime.now().strftime('%Y%m%d_%H%M%S')
- )
- shutil.copy2(file_path, backup_path)
- print('已创建备份文件:', backup_path)
- def ensure_dir_exists(path):
- """确保目录存在(兼容 Python 2/3)"""
- if not os.path.exists(path):
- try:
- os.makedirs(path)
- except OSError as e:
- if e.errno != errno.EEXIST:
- raise
- def update_main_js(file_path):
- """更新main.js文件中的UUID生成方式"""
- if not os.path.exists(file_path):
- print('警告: main.js 文件不存在:', file_path)
- return False
- # 创建备份
- backup_file(file_path)
- try:
- # 读取文件内容
- with open(file_path, 'r') as f:
- content = f.read()
- system = platform.system().lower()
- if system == 'darwin':
- # macOS: 替换 ioreg 命令
- new_content = re.sub(
- r'ioreg -rd1 -c IOPlatformExpertDevice',
- 'UUID=$(uuidgen | tr \'[:upper:]\' \'[:lower:]\');echo \"IOPlatformUUID = \"$UUID\";',
- content
- )
- elif system == 'windows':
- # Windows: 替换 REG.exe 命令
- # 注意:这里使用三重引号来处理复杂的转义
- old_cmd = r'${v5[s$()]}\\REG.exe QUERY HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Cryptography /v MachineGuid'
- new_cmd = r'powershell -Command "[guid]::NewGuid().ToString().ToLower()"'
- new_content = content.replace(old_cmd, new_cmd)
- else:
- print('警告: 不支持的操作系统')
- return False
- # 写入修改后的内容
- with open(file_path, 'w') as f:
- f.write(new_content)
- # 验证修改
- success_marker = 'UUID=$(uuidgen | tr \'[:upper:]\' \'[:lower:]\');echo \"IOPlatformUUID = \"$UUID\";' if system == 'darwin' else 'powershell -Command "[guid]::NewGuid().ToString().ToLower()"'
- if success_marker in new_content:
- print('main.js 文件修改成功')
- return True
- else:
- print('警告: main.js 文件可能未被正确修改,请检查文件内容')
- print('你可以从备份文件恢复:', file_path + '.backup_*')
- return False
- except Exception as e:
- print('修改 main.js 时出错:', str(e))
- return False
- def update_storage_file(file_path):
- """更新存储文件中的ID"""
- # 生成新的ID
- new_machine_id = generate_random_id()
- new_mac_machine_id = generate_random_id()
- new_dev_device_id = generate_uuid()
-
- # 确保目录存在
- ensure_dir_exists(os.path.dirname(file_path))
-
- # 读取或创建配置文件
- if os.path.exists(file_path):
- try:
- with open(file_path, 'r') as f:
- data = json.load(f)
- except ValueError:
- data = {}
- else:
- data = {}
-
- # 更新ID
- data['telemetry.machineId'] = new_machine_id
- data['telemetry.macMachineId'] = new_mac_machine_id
- data['telemetry.devDeviceId'] = new_dev_device_id
- data['telemetry.sqmId'] = '{' + str(uuid.uuid4()).upper() + '}'
-
- # 写入文件
- with open(file_path, 'w') as f:
- json.dump(data, f, indent=4)
-
- return new_machine_id, new_mac_machine_id, new_dev_device_id
- def main():
- """主函数"""
- try:
- # 获取配置文件路径
- storage_path = get_storage_path()
- print('配置文件路径:', storage_path)
-
- # 备份原文件
- backup_file(storage_path)
-
- # 更新ID
- machine_id, mac_machine_id, dev_device_id = update_storage_file(storage_path)
-
- # 输出结果
- print('\n已成功修改 ID:')
- print('machineId:', machine_id)
- print('macMachineId:', mac_machine_id)
- print('devDeviceId:', dev_device_id)
- # 处理 main.js
- system = platform.system().lower()
- if system in ['darwin', 'windows']:
- main_js_path = get_main_js_path()
- if main_js_path:
- update_main_js(main_js_path)
-
- except Exception as e:
- print('错误:', str(e), file=sys.stderr)
- sys.exit(1)
- if __name__ == '__main__':
- main()
复制代码
1 试读已结束,请付费阅读全文。   本文只能试读95%,付费后可阅读全文。  |