第一个策略只在反向交叉时平仓。现在再加入相对入场价的亏损和盈利距离,同时保留原来的交叉平仓。

三种不同出场原因

本例多头持仓可能由三个事件关闭:

  • 价格达到止损单的价位;
  • 价格达到止盈限价单的价位;
  • 快线下穿慢线,且市价平仓单成交。

止损和限价单带价格条件,strategy.close 发出市价平仓单。成交规则可能不同,所以交易表中的价格和时间都要检查。

距离还是具体价格?

strategy.exit 支持两类设置方式:

实参指定什么?
loss亏损距离,单位 tick
profit盈利距离,单位 tick
stop具体止损价
limit具体限价

loss=100 不是 100%,也不一定是 100 单位货币,而是相对入场价相距一百 tick。

DEMO 的 tick 大小为 0.01,因此一百 tick 是 1 价格单位,二百是 2。假设多头入场价为 200,不计滑点和其他成交影响,对应止损 199、目标 202。

完整程序

创建 protected_strategy.py:

"""
@pyne edge
"""
from pynecore.lib import close, color, input, plot, script, strategy, ta


@script.strategy(
    "Crossing Strategy with Exits",
    overlay=True,
    initial_capital=10000,
    default_qty_type=strategy.fixed,
    default_qty_value=1,
    pyramiding=1,
    commission_type=strategy.commission.percent,
    commission_value=0.1,
    slippage=2,
)
def main(
    fast_length: int = input.int(5, title="Fast length", minval=1, maxval=200),
    slow_length: int = input.int(20, title="Slow length", minval=1, maxval=200),
    stop_ticks: int = input.int(100, title="Stop distance (ticks)", minval=1),
    target_ticks: int = input.int(200, title="Target distance (ticks)", minval=1),
):
    fast_average = ta.sma(close, fast_length)
    slow_average = ta.sma(close, slow_length)
    crosses_up = ta.crossover(fast_average, slow_average)
    crosses_down = ta.crossunder(fast_average, slow_average)
    if crosses_up:
        strategy.entry("Long", strategy.long)
    if crosses_down:
        strategy.close("Long")
    strategy.exit("Bracket", "Long", loss=stop_ticks, profit=target_ticks)
    plot(fast_average, "Fast average", color=color.blue, linewidth=2)
    plot(slow_average, "Slow average", color=color.orange, linewidth=2)

Bracket 是出场订单组标识,第二个实参 Long 指定关联哪次入场。loss 和 profit 使用上面两个输入。

每根 K 线都用相同标识执行出场调用,管理指定出场规则,不是每次都建立一份独立的新持仓。

在演示数据运行。Trades 中除了交叉触发的市价平仓,也可能出现 Bracket 出场。

PyneIDE 显示 protected_strategy.py 运行,交易可由止损或目标价出场关闭。
策略保留交叉平仓,同时使用以 tick 指定的止损和目标。

保护性出场何时出现?

程序可以在同一次执行中发出入场及其关联出场指令。执行器能把 tick 距离关联到入场实际成交价。

如果反而根据信号收盘价计算具体 stop,这个价位就以信号价为起点。下一开盘价不同,实际入场到止损的距离也就不同。

应按想表达的规则选择。loss 是相对入场的 tick 距离,stop 是具体价位。

一根 K 线没有记录所有价格步骤

OHLCV 提供开盘、最高、最低、收盘,但不会自动告诉我们内部所有价格的先后顺序。

如果同根最高价达到目标、最低价达到止损,仅这四个数无法判断哪一个先发生。模拟器此时采用执行模型的规则。更低周期的数据可支持更细的检查。

这种情况要单独核查,不要手动总选有利结果。模型假设属于结果的一部分。

止损价也不保证精确成交。如果下一根跳空开在止损另一侧,成交可能比被跳过的价位更差。滑点还可能造成额外偏差。

距离与亏损金额

一单位、点值为 1 的多头持仓,在 tick 为 0.01 时,一百 tick 对应 1 单位货币的价差。数量为十时,金额结果也扩大十倍。

数量、tick 大小和点值共同决定到止损的变动对应多少钱,还要考虑手续费与实际成交条件。

在订单中直接指定 qty,就是这张订单自己的数量。本例使用默认数量,也可在 Properties → Order size 中覆盖。

DEMO 练习的 100、200 tick 只用于示范。在其他品种中,同样数字可能代表不同价格距离和金额。

自己试一试

保持快慢长度、数量和成本不变,分别运行止损/目标为 100/200 与 200/400 的版本。检查同一入场信号最终发生什么。

参考答案

只修改 Inputs 中的 Stop distance (ticks) 和 Target distance (ticks)。距离增大可能让持仓在另一根 K 线、或因另一原因平仓。

交叉平仓在两个版本中都保留,所以目标更远不代表一定持有到目标。出场规则共同起作用。

保存输入后要等待重算结束,再读取新结果。若想以后比较,将两份导出保存为不同名称。

找到出场原因

选择一笔已平仓交易,检查入场价、tick 距离和出场 K 线的 OHLC。根据出场价格与时间,判断哪项规则解释该交易。如果同根触及多个价位,还要考虑执行模型。