找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

4684

积分

0

好友

633

主题
发表于 前天 09:06 | 查看: 61| 回复: 0

本次升级在现有QMT多进程架构基础上,正式为“实盘明细”页面接入真实委托数据。用户可通过该页面实时查询当日全部委托记录,完整展示委托时间、证券代码、证券名称、买卖方向、委托状态、委托量、成交数量、已撤数量、委托价格、成交均价、冻结资金、订单编号及废单原因等字段,支持手动刷新,确保每一笔交易全程可追溯、状态清晰可见。

动量策略轮动系统实盘明细页面
图:实盘明细页面——“当日委托”表格,含高亮成交/废单行与绿色刷新按钮

QMT委托列表界面(含废单状态)
图:QMT原生委托列表,展示多笔“废单”记录,用于比对与调试


整体架构流程

用户操作与数据流转遵循清晰的主-子进程分离设计:

  1. 用户点击导航菜单“实盘明细”  
  2. 页面加载,显示空白表格和刷新按钮  
  3. 用户点击“🔄 刷新”按钮  
  4. Dash回调触发,通过QMT客户端发送 get_orders 命令  
  5. QMT工作进程调用 trader.query_stock_orders() 获取委托数据  
  6. 数据经解析后返回主进程  
  7. 表格自动更新,展示当日委托记录  

Dash主进程与QMT子进程交互架构图
图:进程间通信架构——命令队列(主→子)与响应队列(子→主)双向通道


后端实现:QMTWorker中的 get_orders 方法

QMTWorker 类中新增标准化委托查询方法,兼容QMT API返回格式并统一映射为前端友好结构:

def get_orders(self, cancelable_only=False):
    """获取当日委托"""
    orders = self.trader.query_stock_orders(self.account)
    result = []
    for o in orders:
        result.append({
            # 订单标识
            'order_id': str(o.order_id),
            'order_sysid': str(o.order_sysid),
            # 账户信息
            'account_id': str(o.account_id),
            # 证券信息
            'stock_code': o.stock_code,
            'instrument_name': o.instrument_name,  # 证券名称
            # 价格数量
            'price': float(o.price),
            'order_volume': int(o.order_volume),
            'traded_volume': int(o.traded_volume),
            'traded_price': float(o.traded_price),
            # 时间
            'order_time': datetime.fromtimestamp(o.order_time).strftime('%Y-%m-%d %H:%M:%S'),
            # 类型状态
            'direction': '买入' if o.order_type == 23 else '卖出',
            'status': parse_order_status(o.order_status),
            'status_msg': o.status_msg,  # 废单原因
            'is_cancelable': o.order_status in [50, 52, 55]
        })
    return {'success': True, 'data': result}

✅ 关键处理点:  

  • order_type == 23 映射为“买入”,其余默认为“卖出”(适配QMT标准枚举)  
  • parse_order_status() 为封装的状态码转义函数(如 50 → "全部成交"55 → "废单")  
  • order_time 统一转为可读字符串格式,便于前端按日过滤  

前端展示层:Dash回调逻辑

使用 @app.callback 监听刷新按钮,调用QMT客户端获取数据,并仅保留当日委托(按 order_time 字符串首段日期匹配):

@app.callback(
    Output('orders-detail-table', 'data'),
    [Input('refresh-orders-btn', 'n_clicks')],
    prevent_initial_call=True
)
def update_orders_table(n_clicks):
    """点击刷新按钮时获取委托记录"""
    response = qmt_client.get_orders()
    orders = response.get('data', [])
    table_data = []
    today = datetime.now().strftime('%Y-%m-%d')
    for order in orders:
        # 只显示当日委托
        if order['order_time'].split(' ')[0] != today:
            continue
        table_data.append({
            'order_time': order['order_time'],
            'stock_code': order['stock_code'].split('.')[0],
            'etf_name': order['instrument_name'],
            'direction': order['direction'],
            'status': order['status'],
            'order_volume': f"{order['order_volume']:,}",
            'traded_volume': f"{order['traded_volume']:,}",
            'canceled_volume': f"{order['order_volume'] - order['traded_volume']:,}",
            'price': f"{order['price']:.3f}",
            'traded_price': f"{order['traded_price']:.3f}",
            'frozen_amount': f"¥{(order['order_volume'] - order['traded_volume']) * order['price']:,2f}",
            'order_id': order['order_id'],
            'status_msg': order['status_msg']
        })
    return table_data

⚠️ 注意:canceled_volumeorder_volume - traded_volume 动态计算,避免依赖QMT未暴露字段;金额格式化采用千分位与两位小数,符合金融场景阅读习惯。


前端界面:DataTable配置与条件样式

使用 dash_table.DataTable 渲染表格,并通过 style_data_conditional 实现语义化着色:

dash_table.DataTable(
    id='orders-detail-table',
    columns=[
        {'name': '委托时间', 'id': 'order_time'},
        {'name': '证券代码', 'id': 'stock_code'},
        {'name': '证券名称', 'id': 'etf_name'},
        {'name': '买卖', 'id': 'direction'},
        {'name': '委托状态', 'id': 'status'},
        {'name': '委托量', 'id': 'order_volume'},
        {'name': '成交数量', 'id': 'traded_volume'},
        {'name': '已撤数量', 'id': 'canceled_volume'},
        {'name': '委托价格', 'id': 'price'},
        {'name': '成交均价', 'id': 'traded_price'},
        {'name': '冻结资金', 'id': 'frozen_amount'},
        {'name': '订单编号', 'id': 'order_id'},
        {'name': '废单原因', 'id': 'status_msg'},
    ],
    style_data_conditional=[
        {'if': {'column_id': 'direction', 'filter_query': '{direction} = "买入"'}, 'color': '#e74c3c'},
        {'if': {'column_id': 'direction', 'filter_query': '{direction} = "卖出"'}, 'color': '#2ecc71'},
        {'if': {'column_id': 'status', 'filter_query': '{status} = "全部成交"'}, 'backgroundColor': '#d4edda'},
        {'if': {'column_id': 'status', 'filter_query': '{status} = "部分成交"'}, 'backgroundColor': '#fff3cd'},
    ]
)

💡 效果说明:  

  • “买入”文字标红(#e74c3c)、“卖出”标绿(#2ecc71)  
  • “全部成交”行背景浅绿(#d4edda)、“部分成交”行背景浅黄(#fff3cd)  
  • 所有数值字段均启用千分位分隔符,提升可读性  

技术栈协同说明

本功能深度依赖以下技术组件协同工作:

  • Python:作为核心开发语言,支撑QMT SDK调用、数据解析与Dash服务端逻辑  
  • 数据库/中间件/技术栈:QMT本地客户端本质是轻量级嵌入式数据库+行情/交易双通道中间件,其 query_stock_orders() 接口即为关键数据源  
  • 云栈社区:提供完整系列教程、代码模板与开发者交流支持,助力从原型快速走向实盘  

回顾前序关键升级

本模块建立在前期多项坚实基础之上:

  • 已集成 Backtrader 回测框架,支持真实历史数据轮动策略验证  
  • 实现一键更新行情至本地缓存,回测直接调用本地CSV,大幅提升稳定性与速度  
  • 打通 miniQMT 下单接口,支持从“我的轮动池”页面点击ETF直接下单  
  • 同步QMT账户数据至“我的账户”,涵盖总资产、持仓市值、明细及分布图表  

🔗 前期升级入口(仅保留强相关官方文档链接):  


部署与运行提示

确保环境已安装必要依赖:

pip install dash plotly pandas numpy akshare xtquant

启动服务:

python app.py

访问 http://localhost:8050 即可进入系统,点击左侧菜单栏“实盘明细” → 点击右上角“🔄 刷新”按钮,即可加载最新委托数据。

📌 提示:首次运行需提前配置 miniQMT 模拟账户路径(如 C:\Program Files\国金QMT交易端模拟\userdata_mini),并在 QMTWorker.connect() 中正确传入。




上一篇:实测智谱GLM-5V-Turbo:多模态视觉编码模型如何看懂设计稿自动编程
下一篇:Z80芯片传奇:从餐巾纸融资到48年辉煌,为何最终败给Intel 8086?
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-4-7 17:27 , Processed in 0.740133 second(s), 41 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表