1. 聚宽落幕背后的技术迁移挑战
去年年底聚宽与一创终止合作的消息,在量化圈里炸开了锅。作为一个从2017年就开始用聚宽的老用户,我清楚地记得那天晚上在调试策略时突然弹出的公告弹窗。当时第一反应是:我的几十个实盘策略怎么办?那些依赖聚宽API的自动化交易系统要怎么迁移?
聚宽最让人怀念的是它的策略开发友好性。比如用run_daily()就能轻松实现每日定时执行,get_price()接口获取历史数据也足够稳定。但现实很残酷——当平台方宣布停止服务时,这些便利都变成了技术债务。我统计过,光是基础功能迁移就涉及以下模块:
- 行情数据获取(日线/分钟线/Tick)
- 交易订单管理(委托/成交查询)
- 策略调度系统(定时任务触发)
- 风险控制模块(仓位监控)
最头疼的是定时任务迁移。聚宽的run_weekly()可以精确指定每周几执行,但QMT的run_time()需要自己写时间判断逻辑。我最后用了个土办法:在策略开头加日期判断,配合标志位控制执行次数。
2. QMT平台的技术适配实战
第一次打开QMT的API文档时,我对着密密麻麻的参数列表发了半小时呆。和聚宽相比,QMT更像是个"半成品"——功能都有,但需要自己组装。这里分享几个关键适配点:
2.1 数据库桥接方案
聚宽可以直接在策略里写MySQL操作,但QMT对数据库连接有严格限制。我的解决方案是:
- 在服务器部署Redis作为缓存层
- 用Python脚本定时同步聚宽数据库到Redis
- QMT通过HTTP API获取数据
具体实现时要注意数据格式转换。聚宽的股票代码是"000001.XSHE"格式,QMT需要"000001.SZ"。我写了这样的转换函数:
def convert_jqcode(code): code = code.replace('.XSHE', '.SZ') code = code.replace('.XSHG', '.SH') return code2.2 订单管理系统的重构
聚宽的订单状态是自动更新的,但QMT需要主动查询。我设计了一个状态机来跟踪订单生命周期:
- 已报(OrderStatus=1)
- 部分成交(OrderStatus=2)
- 全部成交(OrderStatus=3)
- 已撤单(OrderStatus=4)
每天开盘前会用delete_data()清空前一天的订单记录,防止数据污染:
def clear_orders(): conn = pymysql.connect(host=DB_HOST, user=DB_USER, password=DB_PWD, database=DB_NAME) with conn.cursor() as cursor: cursor.execute("TRUNCATE TABLE orders") conn.close()3. 关键问题排查与性能优化
迁移过程中最耗时的不是写新代码,而是解决那些意想不到的边界情况。这里记录几个典型案例:
3.1 行情数据延迟问题
QMT的实时行情比聚宽慢2-3秒,这对高频策略是致命的。通过抓包分析发现,问题出在数据压缩传输环节。最终解决方案是:
- 改用UDP协议接收行情
- 本地缓存最新50个Tick
- 增加数据校验机制
优化前后对比:
| 指标 | 优化前 | 优化后 |
|---|---|---|
| 延迟 | 2300ms | 380ms |
| 丢包率 | 1.2% | 0.05% |
3.2 定时任务可靠性提升
QMT的run_time()在系统负载高时会丢失触发。我借鉴了Linux的cron设计思路:
- 每个任务记录最后执行时间
- 主循环每秒检查任务队列
- 超时任务立即补偿执行
核心代码如下:
class TaskManager: def __init__(self): self.tasks = [] def add_task(self, func, interval): self.tasks.append({ 'func': func, 'interval': interval, 'last_run': 0 }) def run(self): while True: now = time.time() for task in self.tasks: if now - task['last_run'] > task['interval']: task['func']() task['last_run'] = now time.sleep(1)4. 迁移后的系统架构设计
现在我的量化系统已经稳定运行了半年多,整体架构分为三个层次:
4.1 数据层
- 使用InfluxDB存储Tick数据
- MySQL存放订单和账户信息
- Redis缓存实时行情
4.2 策略层
- 策略容器隔离运行
- 消息队列解耦策略间通信
- 统一的异常处理框架
4.3 执行层
- QMT作为最终执行终端
- 风控模块前置过滤指令
- 交易日志全链路追踪
最让我满意的是动态加载机制:在不重启QMT的情况下,可以通过HTTP接口热更新策略参数。这得益于Python的importlib模块:
def reload_strategy(strategy_name): module = importlib.import_module(f'strategies.{strategy_name}') importlib.reload(module) return module.Strategy()迁移过程中最大的体会是:量化交易系统不能过度依赖某个平台。现在我的代码里所有平台相关操作都封装成了适配器模式,下次再换平台时,只需要实现新的适配器接口就行。