VeighNa量化社区
你的开源社区量化交易平台 | vn.py | vnpy
Member
avatar
加入于:
帖子: 3
声望: 0

现在遇到一个问题,就是开仓之后,止损和止盈的设置问题。我最开始的设置的止盈是限价单,止损是停止单。但是遇到问题,止损单下单时被拒单,显示仓位冻结。原因可能是止盈限价单挂到了交易所导致仓位被冻结,止损单被拒。对于这种情况应当如何处理。我感觉这是一个挺常见问题吧。如果是都用停止单的话,那么开仓时止盈停止单就已成立,导致开仓即止盈的尴尬局面。如何处理这种情况?

Super Moderator
avatar
加入于:
帖子: 128
声望: 15

这是一个非常经典的CTA策略开发问题。让我先查询一下 VeighNa 的相关文档和策略实现方式。

这是一个非常经典的问题,确实是 CTA 策略开发中经常遇到的场景。让我先解释一下问题的本质,然后给出解决方案。


问题分析

问题根源

你遇到的问题本质上是仓位冻结机制导致的:

订单类型 挂单位置 对仓位的影响
限价止盈单 直接挂到交易所 冻结相应仓位
停止止损单 保存在本地(VeighNa) 触发后才发限价单

当你同时挂出限价止盈单(到交易所)和停止止损单(本地)时:

  1. 限价单挂到交易所后,交易所会冻结对应数量的仓位
  2. 停止单触发时,CTA 引擎尝试发限价单平仓,但发现仓位已被冻结
  3. 导致止损单被拒

为什么"都用停止单"也不行

你提到的尴尬情况——"止盈停止单就已成立,导致开仓即止盈"——是因为:

  • 停止单的触发条件是:价格达到或超过触发价
  • 如果止盈停止单的触发价设置在开仓价附近或更优位置,开仓后立即满足触发条件

解决方案

根据 VeighNa 官方策略的实现惯例,推荐以下几种处理方式:

方案一:只用停止单,动态更新止损价(推荐)

这是 VeighNa 官方示例策略中最常见的做法。核心思路是:

  • 只用停止单,不挂限价止盈单到交易所
  • 通过移动止损来锁定利润
  • 每次 K 线更新时,撤销旧停止单,挂新停止单
def on_bar(self, bar: BarData) -> None:
    # 1. 撤销之前的所有委托(包括之前的止损单)
    self.cancel_all()

    # 2. 更新指标...

    # 3. 持仓状态下更新移动止损
    if self.pos > 0:
        # 更新持仓期间最高价
        self.intra_trade_high = max(self.intra_trade_high, bar.high_price)
        # 计算移动止损价(例如:从最高点回撤一定百分比)
        self.long_stop = self.intra_trade_high * (1 - self.trailing_percent / 100)
        # 发送新的止损停止单
        self.sell(self.long_stop, abs(self.pos), stop=True)

    elif self.pos < 0:
        self.intra_trade_low = min(self.intra_trade_low, bar.low_price)
        self.short_stop = self.intra_trade_low * (1 + self.trailing_percent / 100)
        self.cover(self.short_stop, abs(self.pos), stop=True)

参考策略atr_rsi_strategy.pypulse_strategy.pyaegis_strategy.py

方案二:本地判断止盈条件,触发时发限价单

如果你确实需要固定止盈价,可以在策略中本地判断,满足条件时直接发限价平仓单:

def on_bar(self, bar: BarData) -> None:
    self.cancel_all()

    if self.pos > 0:
        # 本地判断止盈条件
        if bar.high_price >= self.take_profit_price:
            # 满足止盈条件,发限价单平仓
            self.sell(bar.close_price, abs(self.pos))
        else:
            # 未满足止盈,继续挂止损单
            self.sell(self.stop_loss_price, abs(self.pos), stop=True)

方案三:使用 OCO(One Cancels Other)逻辑

VeighNa 的本地停止单机制天然支持类似 OCO 的效果:

def on_bar(self, bar: BarData) -> None:
    # 先撤销所有旧单
    self.cancel_all()

    if self.pos > 0:
        # 同时挂两个停止单(都是本地保存,不冻结交易所仓位)
        # 止盈停止单(上方)
        self.sell(self.take_profit_price, abs(self.pos), stop=True)
        # 止损停止单(下方)
        self.sell(self.stop_loss_price, abs(self.pos), stop=True)

注意:两个停止单都是本地保存的,不会冻结仓位。哪个条件先满足,CTA 引擎就会发出对应的限价单,另一个停止单需要你在 on_trade 中手动撤销。


关键要点总结

方案 优点 缺点
移动止损(推荐) 让利润奔跑,趋势行情收益高 震荡行情可能回吐利润
本地判断止盈 固定止盈,落袋为安 可能错过大趋势
双停止单 类似 OCO,逻辑清晰 需要手动管理另一张单

核心原则

  1. 避免同时挂交易所限价单 + 本地停止单——这会导致仓位冻结
  2. 优先使用移动止损——这是 VeighNa 官方策略的主流做法
  3. 每次 K 线更新先 cancel_all()——确保旧单不会干扰新单

参考来源

  • 文档:cta_strategy.md - 停止单机制说明
  • 策略代码:atr_rsi_strategy.pypulse_strategy.pyaegis_strategy.pysurge_strategy.py
© 2015-2022 上海韦纳软件科技有限公司
备案服务号:沪ICP备18006526号

沪公网安备 31011502017034号

【用户协议】
【隐私政策】
【免责条款】