保持敬畏之心
交易是一场持久战

Pine Script(248):基于周度亏损与周交易频率停止策略

#Pine Script入门教学

如何根据每周损失停止TradingView策略?

一个遭受了重大亏损的策略,需要表现出非凡的业绩才能挽回损失。通常情况下,防范于未然,远比从大额亏损中恢复要容易得多。本文将探讨如何让一个TradingView策略能够基于周度亏损上限来自动停止交易。

在TradingView中基于周度策略亏损停止交易

策略风险的核心当然是亏损。一旦亏损累积,策略需要拿出超常的表现才能勉强回本。一种防止亏损失控的方法,便是设定一个周度的最大亏损上限。当达到这个限额时,策略便暂停本周的交易。

通过这种方式,当市场环境根本不提供机会时,我们的脚本就不会继续盲目交易。让我们看看如何在TradingView Pine中实现这一逻辑。

要让我们的策略脚本能基于周度表现来停止运行,我们将实施以下六个步骤:第一步(可选),创建一个输入项,用于灵活配置最大周度亏损;第二步,获取策略在上周交易结束时的账户权益;第三步,将上周的权益与当前权益进行比较,以计算出策略本周的亏损;第四步,将本周的亏损与设定的最大亏损进行比较;第五步,将比较结果整合进策略的入场逻辑中,这样,一旦达到周度亏损上限,便不会再发送任何入场订单;第六步,在达到周度亏损上限时,平掉策略当前持有的所有市场头寸,从而完全停止交易。让我们来详细分解这些步骤及其所需的代码。

步骤1.(可选)创建一个输入选项

为了在需要调整周度亏损上限时不必修改代码,我们可以创建一个输入选项:

// 通过输入项配置最大周度亏损
maxLoss = input.int(1250, title="周度最大亏损", minval=1) * -1

我们在这里使用 input.int() 函数来创建一个整数输入框。我们将其默认值设为1,250,并通过 minval=1 确保其最小值为1。(确保输入值为正数,可以简化后续的代码逻辑。)

我们将输入值存入 maxLoss 变量。为了方便后续的比较,我们通过乘以 -1 将用户输入的正数(代表亏损额)直接存为一个负数。

(如果你不创建这个可选的输入项,请注意,在后续步骤中,maxLoss 指的是以负数形式表示的周度最大亏损额。)

步骤2. 获取上周的策略权益

追踪周度表现的一个有效方法,是获取策略在上周结束时的账户权益。然后,在本周内,我们将当前权益与这个期初值进行比较。策略权益是初始资金、已平仓交易的累计盈亏以及当前持仓的浮动盈亏三者的总和。

以下是我们如何获取上周的这个数值:

// 计算出上周交易结束时的策略权益
equityLastWeek = 0.0
equityLastWeek := dayofweek == dayofweek.monday and dayofweek != dayofweek[1] ?
     strategy.equity[1] : equityLastWeek[1]

这里,我们首先声明了一个持久变量 equityLastWeek。然后,通过条件运算符(?:)来为其赋予实际值。

这个条件包含两个部分:第一部分检查当前K线的星期(dayofweek)是否为星期一(dayofweek.monday)。第二部分则检查当前K线是否为本日的第一根K线(通过判断 dayofweek 是否不等于其前一根K线的值来实现)。

只有当这两个条件同时成立时,才意味着策略正在处理本周的第一根K线。此时,上周的期末权益就是前一根K线收盘时的权益(strategy.equity[1])。

如果当前K线不是周一早上的第一根,那么条件运算符就会让 equityLastWeek 保持其前一根K线的值。通过这种方式,equityLastWeek 变量每周只在周一开盘时更新一次。在其他时间,它会静态地保存着上周末的权益值(这正是我们所需要的)。

(如果你的交易周是从周日开始的,只需将上述代码中的 dayofweek.monday 替换为 dayofweek.sunday 即可。)

步骤3. 确定策略的本周亏损

有了上周的期末权益,我们就可以计算策略当前的周度表现:

// 计算策略的本周亏损
weeklyLoss = strategy.equity - equityLastWeek

为了计算策略的周度亏损,我们用其当前权益(strategy.equity)减去上周末的权益(equityLastWeek)。我们将结果存入 weeklyLoss 变量以备后用。

步骤4. 将周度表现与最大亏损进行比较

现在,我们可以将策略的周度表现与其最大亏损限额进行比较。由于后续步骤也需要这个判断结果,最简单的方法是将其存入一个布尔变量中。

// 判断策略是否仍被允许交易
okToTrade = weeklyLoss > maxLoss

这段代码检查 weeklyLoss 是否大于 maxLoss(我们在步骤1中创建的输入变量,默认值为-1,250)。只要策略的周度表现仍高于这个亏损下限,okToTrade 变量就为 true,否则为 false

步骤5. 在发送入场订单前检查周度亏损

现在我们有了一个布尔变量 okToTrade,它告诉我们策略是应该继续交易(true)还是暂停(false)。我们可以将这个变量整合到我们的多空入场条件中。例如:

// 提交订单
if okToTrade and enterLong
    strategy.entry("EL", strategy.long)

if okToTrade and enterShort
    strategy.entry("ES", strategy.short)

第一个 if 语句只有在 okToTradeenterLong 同时为 true 时,才会通过 strategy.entry() 提交一个做多订单。第二个 if 语句同理。

一旦策略触及了其最大周度亏损,okToTrade 就会变为 false。这反过来会阻止 strategy.entry() 发送任何新的多头或空头订单,从而停止策略的交易活动。

请注意,上述代码中的 enterLongenterShort 变量只是你策略实际入场条件的占位符。你的代码可能会有所不同,但核心思想不变:在发送任何新的入场订单(无论是通过 strategy.entry() 还是 strategy.order())之前,都必须先检查 okToTrade 的状态。

步骤6. 达到周度亏损时平掉所有仓位

在最后一步,当达到周度亏损上限时,我们平掉所有持仓。这样,亏损就不会因为市场头寸的继续持有而进一步恶化。我们退出策略的所有持仓:

// 当达到周度亏损时,平掉所有持仓
if not okToTrade
    strategy.close_all()

这个 if 语句使用 not 逻辑运算符来判断 okToTrade 是否为 false。如果是,就意味着策略的周度亏损已达到上限。

在这种情况下,我们执行 strategy.close_all() 函数。如果策略当时有持仓,该函数会发送一个市价单来平掉所有仓位。

有两点值得注意:一是由于我们在发送任何入场订单前都已检查了 okToTrade,因此在平仓后,我们无需再做任何事。换言之,由于 okToTrade 的值为 false,我们的策略现在已经完全停止了交易。二是因为我们是通过市价单来平仓的,由于滑点和佣金的存在,最终的亏损可能会比我们设定的最大亏损略差一些。

示例策略:基于周度亏损停止交易

下方的代码将以上六个步骤整合进了一个完整的脚本中。该示例策略交易的是两条指数移动平均线(EMA)的交叉。

这个交易过程会一直持续,直到触及周度亏损上限。一旦发生这种情况,交易便会停止,策略必须等待下一周才能重新开始。该脚本还在图表上绘制了其周度亏损和最大亏损的水平线,这使得追踪策略在周内的表现变得非常容易。完整的策略代码如下:

//@version=5
strategy(title="在周度亏损后停止交易", overlay=false,
     default_qty_type=strategy.fixed, default_qty_value=10)

// 步骤1:
// 通过输入项配置最大周度亏损
maxLoss = input.int(1250, title="周度最大亏损", minval=1) * -1

// 计算移动平均线
fastMA = ta.ema(close, 5)
slowMA = ta.ema(close, 25)

// 定义交易条件
enterLong  = ta.crossover(fastMA, slowMA)
enterShort = ta.crossunder(fastMA, slowMA)

// 步骤2:
// 计算出上周交易结束时的策略权益
equityLastWeek = 0.0
equityLastWeek := dayofweek == dayofweek.monday and dayofweek != dayofweek[1] ?
     strategy.equity[1] : equityLastWeek[1]

// 步骤3:
// 计算本周的策略亏损
weeklyLoss = strategy.equity - equityLastWeek

// 在图表上显示周度亏损和触发水平线
plot(math.min(weeklyLoss, 0), style=plot.style_area, 
     color=color.new(color.red, 85))
hline(0, color=color.orange, linestyle=hline.style_solid)
hline(maxLoss, color=color.red, linestyle=hline.style_solid, linewidth=3)

// 步骤4:
// 判断策略是否仍被允许交易
okToTrade = weeklyLoss > maxLoss

// 步骤5:
// 提交订单
if okToTrade and enterLong
    strategy.entry("EL", strategy.long)

if okToTrade and enterShort
    strategy.entry("ES", strategy.short)

// 步骤6:
// 当达到周度亏损时,平掉所有持仓
if not okToTrade
    strategy.close_all()

让我们看看这个策略在图表上的行为。在下方的富时100指数CFD图表上,我们看到脚本在10号建立了一个空头仓位。该交易表现不佳,并最终导致策略触及了其最大周度亏损。

当这种情况发生时,策略平掉了仓位并暂停了本周的所有交易:

下方的原油CFD图表则展示了一个更长期的视角。这里,策略首先触及了其周度亏损。然后,新的一周开始了,策略得以重新尝试。不幸的是,情况并未好转:脚本再次达到了其最大亏损上限,并再次停止了交易。

请注意,如果你想限制一个策略的日内亏损,你不必像本文这样编写自定义代码。因为TradingView已经为此提供了一个内置的风险管理函数。通过 strategy.risk.max_intraday_loss() 函数,我们可以让策略在达到一定的日内亏损后,暂停当日的交易。要了解更多限制和管理TradingView策略风险的方法,请浏览我们的风险管理分类文章。

如何限制TradingView策略在一周内的交易频率?

一个交易频繁的策略通常会产生显著的佣金和滑点成本。在行情好的时候,这或许不成问题。但当市场条件不利时,这些额外的成本只会让策略的表现雪上加霜。本文将探讨如何限制一个TradingView策略的每周交易次数。

拒绝过度交易:基于每周交易频率的策略熔断机制

理论上,一个策略只应在具有正期望值时才进行交易。但在现实中,任何策略都会经历亏损期。有时市场条件会变得异常动荡或不可预测,导致策略频繁出错。在这些时候,限制策略的交易活动,比盲目交易、越陷越深要明智得多。

一个有效的选项是限制在特定时间周期内的交易频率。虽然TradingView为日内交易提供了内置函数 strategy.risk.max_intraday_filled_orders(),但并非所有策略都适用于日内时间框架。

即便对于日内策略,基于一个更长的时间周期(如周)来限制交易,也可能是一个好主意。这样,交易活跃和交易稀疏的日子可以相互抵消,从而得到一个更平滑的风险控制。接下来,让我们看看如何实现对TradingView策略的每周交易次数限制。

要让我们的TradingView策略在一周内交易达到一定次数后自动停止,需要完成以下任务:第一步(可选),使用输入选项来设定每周的最大交易次数;第二步,获取并记录上周末收盘时的策略总交易数;第三步,在本周的每一根K线上,用当前的总交易数减去上周末的记录,从而计算出本周已发生的交易次数;第四步,将本周的交易次数与设定的上限进行比较;第五步,仅在未达到每周交易上限时才提交新的开仓订单;第六步,一旦达到上限,立即平掉所有当前持有的仓位。让我们逐一分解这些步骤,并看看需要哪些代码来实现。

步骤1.(可选)使用输入选项设定每周交易上限

为了方便地调整每周最大交易次数,我们可以创建一个输入选项:

// 为每周允许的交易次数创建一个输入项
maxTrades = input.int(20, title="每周最大交易次数", minval=1)

我们使用 input.int() 函数创建一个整数输入框,默认值为20。我们将这个输入值保存在 maxTrades 变量中,以便后续步骤使用。(如果你不需要输入选项,只需在后续步骤中用你自己的方式设定的周交易上限值替换 maxTrades 即可。)

步骤2. 获取上周末的总交易数

要计算策略的交易次数,最简单可靠的方法是结合使用两个内置变量:strategy.closedtrades(已平仓交易数)和 strategy.opentrades(未平仓交易数)。

由于这两个变量返回的是整个回测期间的累计总数,我们需要一种方法来截取上周末的数值。然后,在本周内,我们就可以通过与这个基准值比较来得出本周的交易次数。实现代码如下:

// 记录上周末收盘时的总交易数
tradesLastWeek = 0

tradesLastWeek := if dayofweek == dayofweek.monday and dayofweek != dayofweek[1]
    strategy.closedtrades[1] + strategy.opentrades[1]
else
    tradesLastWeek[1]

这段代码的核心在于 if dayofweek == dayofweek.monday and dayofweek != dayofweek[1] 这个条件。它能精确地定位到每周一的第一根K线。在这一刻,我们通过历史引用操作符 [1] 来获取上一根K线(即上周五收盘时)的已平仓和未平仓交易总数,并将其作为本周的基准储存在 tradesLastWeek 变量中。在一周的其他时间里,这个变量的值通过 tradesLastWeek[1] 保持不变,从而实现了每周仅更新一次的效果。

步骤3. 计算本周已发生的交易次数

有了上周末的交易数基准,计算本周的交易次数就变得非常简单了:

// 计算本周已发生的交易次数
weeklyTrades = (strategy.closedtrades + strategy.opentrades) -
     tradesLastWeek

我们将当前的总交易数(已平仓 + 未平仓)减去上周末记录的 tradesLastWeek,差值即为本周内发生的交易次数。

步骤4. 比较当前周交易数与上限

现在,我们可以判断策略是否已达到每周的交易上限:

// 判断是否仍可进行交易
okToTrade = weeklyTrades < maxTrades

okToTrade 是一个布尔变量。如果本周交易次数 weeklyTrades 小于我们设定的上限 maxTradesokToTrade 就为 true,否则为 false

步骤5. 在开仓条件中加入周交易频率检查

有了 okToTrade 这个明确的交易开关,我们就可以将其整合到我们的开仓逻辑中:

// 在提交订单前,加入对周交易频率的考量
if okToTrade and enterLong
    strategy.entry("EL", strategy.long)
if okToTrade and enterShort
    strategy.entry("ES", strategy.short)

只有当 okToTradetrue 时,策略的开仓条件(enterLongenterShort)才可能被满足,从而提交新的订单。一旦周交易次数达到上限,okToTrade 变为 false,策略便会停止响应新的交易信号。

重要提示:请确保在你策略中所有可能产生新仓位的代码(包括 strategy.entry()strategy.order())前都加入了 okToTrade 这个条件判断,否则此风控逻辑将无法生效。

步骤6. 达到上限后立即平仓

最后一步是,在达到周交易上限后,立即清空所有持仓,彻底停止策略的交易活动。

// 当达到周交易上限时,平掉所有当前持仓
if not okToTrade
    strategy.close_all()

我们使用 not okToTrade 来判断 okToTrade 是否为 false。一旦为 false,就调用 strategy.close_all() 函数,它会发送一个市价单来平掉所有当前持仓。

通过结合步骤5和步骤6,我们便实现了一个完整的周交易频率熔断机制。

示例策略:实现基于每周交易次数的熔断

下方的完整策略脚本融合了以上所有步骤。它基于均线交叉进行交易,直到每周20笔的交易上限被触发。届时,策略将停止开新仓,并清空已有仓位。当新的一周开始时,计数器重置,策略恢复正常交易。策略的完整代码如下:

//@version=5
strategy(title="限制每周交易", overlay=false, precision=0,
     default_qty_type=strategy.fixed, default_qty_value=20)

// 步骤 1: 设定每周最大交易次数
maxTrades = input.int(20, title="每周最大交易次数", minval=1)

// 计算指标和交易条件
fastMA = ta.ema(close, 5)
slowMA = ta.ema(close, 25)
enterLong  = ta.crossover(fastMA, slowMA)
enterShort = ta.crossunder(fastMA, slowMA)

// 步骤 2: 记录上周末的总交易数
tradesLastWeek = 0
tradesLastWeek := if dayofweek == dayofweek.monday and dayofweek != dayofweek[1]
    strategy.closedtrades[1] + strategy.opentrades[1]
else
    tradesLastWeek[1]

// 步骤 3: 计算本周交易数
weeklyTrades = (strategy.closedtrades + strategy.opentrades) -
     tradesLastWeek

// 在图表上可视化周交易数和上限
plot(weeklyTrades, style=plot.style_columns,
     color=weeklyTrades >= maxTrades ? color.orange : color.teal)
hline(maxTrades, color=color.red, linestyle=hline.style_solid,
     linewidth=2)
hline(0, linestyle=hline.style_solid, color=color.gray)

// 步骤 4: 判断是否可以交易
okToTrade = weeklyTrades < maxTrades

// 步骤 5: 提交开仓订单
if okToTrade and enterLong
    strategy.entry("EL", strategy.long)
if okToTrade and enterShort
    strategy.entry("ES", strategy.short)

// 步骤 6: 达到上限后平仓
if not okToTrade
    strategy.close_all()

由于策略会在图表上绘制每周的交易数量,我们可以很方便地追踪这个值。在下方的截图中,每周交易数缓慢增长至20。当达到这个水平时,策略发送了一个平仓订单来退出已有的空头仓位。然后,在本周剩余的时间里,脚本没有再提交任何新的订单。

下方的图表展示了一个更长的时间周期。我们可以看到,一旦新的一周开始,策略便重新开始交易了:

要了解更多想法和灵感,可以查阅TradingView风险管理的相关主题分类。

赞(0)
未经允许不得转载:图道交易 » Pine Script(248):基于周度亏损与周交易频率停止策略
分享到

评论 抢沙发

登录

找回密码

注册