Skip to content

固定价差回转:成交后反向挂一档(QMT / PTrade)

库里叫「回转交易」「固定价差做 T」。不是选股,也不是动量轮动。先在基准价上下挂限价,整笔满成后再按固定价差反向挂一档,循环。股票常见一档 0.01,ETF 常见 0.001。档位数、股数、价差都是示例,不是操作指令。不构成投资建议,不代操盘。

手册:passorder · order · 委托回调 · get_snapshot

逻辑简述

  1. 开盘先铺档。基准价优先用昨天记下的回转价,没有就用昨收。向上挂 N 档卖、向下挂 M 档买。
  2. 满成才回转deal_callback / on_trade_response 里把剩余量减到 0,才按委托价加减一档反向挂,不要用零碎成交价当下一档。
  3. 价差分品种。股票两位小数,ETF 三位。混用会废单。
  4. 状态要落盘。回转价写进 pkl / json,文件名带上价差,多实例才不会互相覆盖。隔夜券商撤单后,盘前按 last_side 决定先挂买还是先挂卖。
  5. 限流。每秒笔数、9:25–9:30 集合竞价窗口、总回转笔数都要卡,否则柜台拒单。

PTrade 还有另一套「固定价差做 T」:每标的只维持一笔,基准价 P 是上一笔整笔成交均价,买限价 min(P-A, 卖一),卖限价 max(P+A, 买一),用快照夹盘。和「铺多档 + 回调回转」是同一类,状态机更严。

QMT 版本

上交所用 .SH。板块当股票池。initset_account,成交走 deal_callback。回转价文件按 stock0_01_etf0_001 这种后缀区分。

python
#encoding:gbk
def init(C):
    try:
        g.acct = account
        g.acct_type = accountType
    except NameError:
        g.acct = ''
        g.acct_type = 'STOCK'
    C.set_account(g.acct)
    g.diff_stock = 0.01
    g.diff_etf = 0.001
    g.mode = 3            # 1 只股票 2 只 ETF 3 都转
    g.reversal_price_source = 'order'  # 次日铺档用委托价;回转当下仍用委托价±1档
    # 回转价落到策略目录,文件名带价差,避免多实例抢同一份 pkl

def order_callback(C, orderInfo):
    # 记下 order_id -> 代码、限价、方向、原数量、剩余数量
    pass

def deal_callback(C, dealInfo):
    deal_id = dealInfo.m_strOrderSysID
    # trade_dict[deal_id]['res_vol'] -= 本笔成交量
    # 剩余不为 0 就返回
    code = trade_dict[deal_id]['code']
    is_stock = code[0] in '036984'
    diff = g.diff_stock if is_stock else g.diff_etf
    digits = 2 if is_stock else 3
    src = trade_dict[deal_id]['price']
    if trade_dict[deal_id]['flag'] == 49:      # 原卖,回转买
        px = round(src - diff, digits)
        op = 23
    else:                                      # 原买,回转卖
        px = round(src + diff, digits)
        op = 24
    passorder(op, 1101, g.acct, code, 11, px, trade_dict[deal_id]['all_vol'],
              '策略1', 2, '', C)

信用户买入常见 33 担保品 / 27 融资,卖出 34。不是两融标的不要硬走 27passorder 返回不等于成交。

铺档在 9:31 或启动时跑:有持仓可以跳过「现价远高于基准就不出买」那条,避免空仓时把资金挂死在天上。无仓且现价已经比基准高一截,本轮可以不铺。现价用 get_full_tick,盘前空了再用昨收。

PTrade 版本

上交所用 .SS。要回转手工单,初始化里 set_parameters(receive_other_response='1'),否则 on_trade_response 收不到策略外成交。

python
def initialize(context):
    g.diff_stock = 0.01
    g.diff_etf = 0.001
    g.mode = 3
    set_parameters(receive_other_response='1')
    # reversal_prices.json 放 get_research_path()

def on_trade_response(context, trade_list):
    for t in trade_list:
        if not _is_full_fill(t):
            continue
        security = normalize_stock_code(t.security)
        diff = g.diff_stock if is_stock(security) else g.diff_etf
        digits = 2 if is_stock(security) else 3
        src = float(t.limit_price)          # 回转按委托价,不是成交价
        if t.side == 'BUY':
            order(security, -t.volume, limit_price=round(src + diff, digits))
        else:
            order(security, t.volume, limit_price=round(src - diff, digits))

「固定价差做 T」那套不铺多档,每标的状态是 空仓可买 → 挂买中 → 可卖出 → 挂卖中。P 用整笔成交均价,不要用持仓成本。夹盘:

python
buy_px = min(P - A, ask1)   # 再和涨跌停比一遍
sell_px = max(P + A, bid1)

五档来自 get_snapshotbid_grp / offer_grp。快照大约 3 秒一帧,见 快照 3 秒。回测慎用快照,用 K 线近似盘口。get_order 可能返回对象或 list,满成后柜台有时不再返回该单,要用当日委托簿补链。

两边都容易踩的坑

  1. 从 QMT 拷到 PTrade,先换 .SH.SS。见 .SS / .SH
  2. 回转用委托价加减档,不要用零碎成交价,否则档位会漂。
  3. 部分成交不要反向。必须整笔数量满成。
  4. 股票两位、ETF 三位。限价精度错了直接废单。
  5. 回测几乎验不了成交主推和隔夜撤单。先仿真把委托、成交、持仓对清楚。
  6. 不要把池外成交默认回转,除非你明确打开开关。

完整源码见知识星球附件,这里只放逻辑和片段。

相关:API 查询 · 热门问题 · 关注 / 知识星球

完整讨论和附件在 知识星球 Kimi量化研究所