如何根据每周损失停止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 语句只有在 okToTrade 和 enterLong 同时为 true 时,才会通过 strategy.entry() 提交一个做多订单。第二个 if 语句同理。
一旦策略触及了其最大周度亏损,okToTrade 就会变为 false。这反过来会阻止 strategy.entry() 发送任何新的多头或空头订单,从而停止策略的交易活动。
请注意,上述代码中的 enterLong 和 enterShort 变量只是你策略实际入场条件的占位符。你的代码可能会有所不同,但核心思想不变:在发送任何新的入场订单(无论是通过 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 小于我们设定的上限 maxTrades,okToTrade 就为 true,否则为 false。
步骤5. 在开仓条件中加入周交易频率检查
有了 okToTrade 这个明确的交易开关,我们就可以将其整合到我们的开仓逻辑中:
// 在提交订单前,加入对周交易频率的考量
if okToTrade and enterLong
strategy.entry("EL", strategy.long)
if okToTrade and enterShort
strategy.entry("ES", strategy.short)
只有当 okToTrade 为 true 时,策略的开仓条件(enterLong 或 enterShort)才可能被满足,从而提交新的订单。一旦周交易次数达到上限,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风险管理的相关主题分类。






