迅投miniQMT实盘大单拆单批量下单方法的实现

       前面介绍了如何利用迅投miniQMT实现同花顺自选股的盘中实时监控方法,本文和大家一起分享如何利用迅投miniQMT在实盘中实现大单拆单批量下单。

       特别提示:本文只从技术层面介绍如何实现大单拆单进行批量下单,不对读者的实际盈亏负责。进行实盘下单前,请务必检查好各参数!

 本专栏文章:

使用迅投miniQMT实时监控同花顺自选股,实现自动交易

使用python获取同花顺免费版和同花顺远航版自选股数据用于量化交易

使用python将选股策略选股结果自动更新同花顺【远航版】自选股

使用python将选股策略选股结果自动更新同花顺【免费版】自选股

迅投miniQMT实盘大单拆单批量下单方法的实现

需求分析

进行实盘交易时,避免对市场造成太大冲击或者隐藏实际交易意图,有时可能需要将一个大单分成多个小单逐步执行,这时就需要进行大单拆单,且保证拆单后的每单买卖数量符合交易所交易规则。

难点分析

对大单进行拆单,难点在于如何进行拆单,且保证拆单后的每单数量符合交易所交易规则。

比如,想买入某股票1000股,分拆成3次买入,怎么拆分呢?如果用1000除以3的话,每单333.33,显然不符合交易规则。

再如,想买入某科创板股票400股,分拆成4次,每次100股,这也不符合上交所关于科创板股票的交易规则。

那该如何处理呢?

本文的拆分思路是,在确保每次下单的数量符合交易所的最小交易单位的前提下(为简化起见,本文只是平均拆单,随机拆单方法后续介绍),将余数加到最后一个订单上。

计算每单数量:

base_quantity = total_quantity // order_nums
# 余数处理
remainder = total_quantity % (order_nums * min_trading_unit) 
# 调整数量符合最小交易单位
adjusted_quantity = (base_quantity // min_trading_unit) * min_trading_unit
if adjusted_quantity == 0:
    raise ValueError("拆单后单笔数量小于最小交易单位")

处理余数

for i in range(order_nums):
    # 计算当次委托量(最后一笔加上余数)
    order_volume = adjusted_quantity
    if i == order_nums - 1:
        order_volume += remainder

功能说明

1.参数校验:检查买卖方向、数量有效性等基础参数

2.智能拆单:

  • 自动计算基础委托量

  • 最后一单自动处理余数

  • 保证每笔委托符合最小交易单位

3.异常处理:捕获下单异常并继续执行后续委托

4.日志输出:实时显示下单进度,可通过参数关闭

说明:

1.本文未对下单结果进行跟踪,如有需要,请自行修改;

2.如需市价委托,请自行增加交易时间的判断。

函数说明

def split_order(xt_trader, account, stock_code, price, total_quantity, order_type, price_type='limit', order_nums=5, interval=3, min_trading_unit=100, strategy_name='', order_remark='', is_log=True):
    pass
参数:
    xt_trader (str): XtQuantTrader对象
    account (str): StockAccount对象
    stock_code (str): 股票代码 (e.g. '600519.SH')
    price (float): 委托价格 (市价单可设为0)
    total_quantity (int): 总委托数量
    order_type (str): 买卖方向 ('buy'/'sell')
    price_type (str): 订单类型 ('limit'限价单/'market'市价单)
    order_nums (int): 拆单次数 (默认5次)
    interval (int): 下单间隔(秒) (默认3秒)
    min_trading_unit (int): 最小交易单位 (默认100,科创板200)
    is_log (bool): 是否打印执行日志

返回:
    list: 生成的订单ID列表

使用方法

if __name__ == '__main__':
    # init_xttrader()函数详见https://blog.csdn.net/tzzqn2008/article/details/145634836
    xt_trader, acc = init_xttrader()
    orders = split_order(
        xt_trader=xt_trader,
        account=acc,
        stock_code='300382.SZ',
        price=19.99,
        total_quantity=300,
        order_type='sell',
        price_type='limit',
        order_nums=3,
        interval=1,
        min_trading_unit=100
    )

结果如下图所示:

全部代码

其中:init_xttrader()函数是生成XtQuantTrader对象和StockAccount对象,详见《使用迅投miniQMT实时监控同花顺自选股,实现自动交易》

import time
import re
from xtquant import xtconstant
from utils.func import init_xttrader
import random


def split_order(xt_trader, account, stock_code, price, total_quantity, order_type, price_type='limit', order_nums=5, interval=3, min_trading_unit=100, strategy_name='', order_remark='', is_log=True):
    """
    拆单下单函数 - 将大单拆分为多个符合规则的小单
    参数:
        xt_trader (str): XtQuantTrader对象
        account (str): StockAccount对象
        stock_code (str): 股票代码 (e.g. '600519.SH')
        price (float): 委托价格 (市价单可设为0)
        total_quantity (int): 总委托数量
        order_type (str): 买卖方向 ('buy'/'sell')
        price_type (str): 订单类型 ('limit'限价单/'market'市价单)
        order_nums (int): 拆单次数 (默认5次)
        interval (int): 下单间隔(秒) (默认3秒)
        min_trading_unit (int): 最小交易单位 (默认100)
        is_log (bool): 是否打印执行日志

    返回:
        list: 生成的订单ID列表
    """

    # 参数校验
    if not re.match(r'([0-9]{6})(.SH)$|([0-9]{6})(.SZ)|([0-9]{6})(.BJ)$', stock_code):
        raise ValueError("股票代码不正确,请确保股票代码带市场编码,如600001.SH")

    if str.upper(order_type) not in ['BUY', 'SELL']:
        raise ValueError("买卖方向错误,应为'BUY'或'SELL'")

    if str.upper(price_type) not in ['LIMIT', 'MARKET']:
        raise ValueError("买卖方向错误,应为'BUY'或'SELL'")

    if total_quantity <= 0:
        raise ValueError("委托数量必须大于0")

    if str.startswith(stock_code, '688'):
        min_trading_unit = 200


    # 计算基础手数
    base_quantity = total_quantity // order_nums
    # 余数处理
    remainder = total_quantity % (order_nums * min_trading_unit)  
    # 调整数量符合最小交易单位
    adjusted_quantity = (base_quantity // min_trading_unit) * min_trading_unit
    if adjusted_quantity == 0:
        raise ValueError("拆单后单笔数量小于最小交易单位")

    # 转换order_type为miniQMT的order_type
    order_type = xtconstant.STOCK_BUY if str.upper(order_type) == 'BUY' else xtconstant.STOCK_SELL
    # 如果是市价委托,将price设置为0
    price = price if str.upper(price_type) == 'LIMIT' else 0
    # 转换price_type为miniQMT的price_type
    price_type = xtconstant.FIX_PRICE if str.upper(price_type) == 'LIMIT' else xtconstant.LATEST_PRICE
    # 设置strategy_name
    if strategy_name == '':
        strategy_name = 'spit_strategy'
    # 设置order_remark
    if order_remark == '':
        order_remark = [f"spit_strategy_{j + 1}" for j in range(order_nums)]
    orders = []
    try:
        for i in range(order_nums):
            # 计算当次委托量(最后一笔加上余数)
            order_volume = adjusted_quantity
            if i == order_nums - 1:
                order_volume += remainder

            # 生成实盘委托
            # 实盘打开下一行注释,请务必检查好相关参数。打开注释代表实盘盈亏自负!
            # order_id = xt_trader.order_stock(account, stock_code, order_type, order_volume, price_type, price, strategy_name, order_remark[i])

            if order_id:
                orders.append(order_id)
                if is_log:
                    print(f"[{time.strftime('%H:%M:%S')}] 已发送【{'买' if order_type == 23 else '卖'}】单 #{i + 1}: "
                          f"{order_volume}股 @ {price if price else '市价'} 订单ID:{order_id} 策略名:{strategy_name}  订单备注:{order_remark[i]}")
            else:
                if is_log:
                    print(f"第 {i + 1}/{order_nums} 次下单失败")
            # 等待间隔
            if i < order_nums - 1:
                time.sleep(interval)
    except Exception as e:
        print(f"下单异常: {str(e)}")
        return orders
    return orders


if __name__ == '__main__':
    xt_trader, acc = init_xttrader()
    orders = split_order(
        xt_trader=xt_trader,
        account=acc,
        stock_code='300382.SZ',
        price=19.99,
        total_quantity=300,
        order_type='sell',
        price_type='limit',
        order_nums=3,
        interval=0, 
        min_trading_unit=100
    )

    print('*' * 50)
    print(orders)

码字不易,原创更不易,如您觉得本文对您有帮助,麻烦动动您富贵的小手,点赞、收藏、关注、订阅!!!

你可能感兴趣的:(量化交易,python,量化交易,miniQMT)