如何修复TradingView的”无法在学习脚本中使用策略功能”错误?
在TradingView中,我们能创建的脚本主要有两种:指标(indicators)和策略(strategies)。前者通常用于在图表上绘图和标记符号,而后者则可以模拟交易并回测交易思想。尽管两者共享大量的Pine Script代码,但某些专属于策略的代码元素是不能在指标中使用的。本文将探讨当我们在指标中误用策略代码时会触发何种错误,以及如何解决。
剖析TradingView的’can’t use strategy functions’错误
TradingView的指标和策略之所以易于上手,很大程度上是因为它们共享了许多通用的代码。大多数我们能为指标编写的功能同样也适用于策略。但某些函数和变量是特定脚本类型独有的。当我们试图混用时,就会遇到错误。
其中一个常见的错误就是’can’t use strategy functions in study script’(无法在研究脚本中使用策略函数)。当这个错误发生时,图表上首先会显示一个通用的无法编译脚本的提示:
这个提示本身帮助不大。幸运的是,Pine编辑器的控制台窗口中提供了更详细的信息,例如:
Processing script...
You can't use strategy functions (strategy.position_avg_price) in study script. Please replace 'study' with 'strategy'.
Script 'Error example' has been saved
(你不能在研究脚本中使用策略函数(strategy.position_avg_price)。请将’study’替换为’strategy’。)
这条错误信息非常明确:它不仅指出了错误的原因,还点名了我们试图误用的具体代码元素。
修复’can’t use strategy functions in study script’错误
‘can’t use strategy functions in study script’这个错误,发生在我们试图在指标脚本中使用专属于策略的变量或函数时。由于指标脚本的设计初衷不包含交易功能,TradingView会在我们尝试这么做时触发错误。
幸运的是,修复这个错误非常简单,因为错误信息已经给出了明确的指引。第一步,仔细阅读完整的错误信息,特别注意括号中提到的代码元素,例如 strategy.position_avg_price,这个变量或函数就是问题的根源。第二步,你需要决定如何处理这个不被允许的策略代码:如果你的脚本逻辑并不依赖于这个变量或函数,那么最简单的办法就是直接删除它并保存脚本,如果之后又出现了新的同类错误,只需重复此步骤即可;如果你确实需要使用这个变量或函数的功能,那么你就需要将整个脚本的类型从指标(indicator/study)更改为策略(strategy),这正是错误信息提示 Please replace 'study' with 'strategy' 的含义。
提示:虽然错误信息说的是策略函数,但实际上也有几个策略变量是无法在指标中使用的。因此,在编写指标时,也要留意不要误用这些策略独有的变量。
关于study script:在错误信息中,你可能会看到’study script’这个词。在这里,它只是指标(indicator)的另一个名字。在TradingView的语境中,study几乎总是指indicator。为了避免混淆,本文更倾向于使用指标和策略这两个更明确的术语。
接下来,让我们通过几个例子来看看如何修复这个错误。
错误示例1:在指标中绘制策略数据
一个常见的错误场景,是在指标脚本中尝试绘制策略的绩效数据。
例如,在一个指标中这样写:
//@version=5
indicator(title="错误示例", overlay=true)
plot(strategy.grossloss, color=color.blue, linewidth=2)
Processing script...
You can't use strategy functions (strategy.grossloss) in study script. Please replace 'study' with 'strategy'.
Script 'Error example' has been saved
这会引发错误,因为我们不能在指标中使用策略的总亏损变量(strategy.grossloss)。
正确的做法是将 plot() 函数从指标代码中移动到策略脚本内部。因为TradingView的策略脚本也具备绘图功能,我们完全可以在策略脚本中直接绘制其绩效数据,而无需创建独立的指标。修改后的策略脚本可能如下:
//@version=5
strategy(title="策略示例", overlay=false, pyramiding=10)
// ...交易逻辑...
if longCondition
strategy.entry("Enter Long", strategy.long)
if shortCondition
strategy.entry("Enter Short", strategy.short)
// 在策略脚本中直接绘制总亏损
plot(strategy.grossloss, color=color.blue, linewidth=2)
错误示例2:使用策略数据生成警报
不幸的是,并非所有’can’t use strategy functions in study script’错误都能被完美解决。在本文写作之时,TradingView的策略脚本尚不支持创建警报,而指标脚本则可以。
那么,我们是否可以曲线救国,通过一个指标来读取策略的持仓信息并创建警报呢?例如:
//@version=5
indicator(title="错误示例", overlay=true)
smaValue = ta.sma(close, 50)
plot(smaValue, color=color.orange)
alert = close > smaValue and strategy.position_size != 0
alertcondition(condition=alert,
message="价格在SMA上方且有持仓")
Processing script...
You can't use strategy functions (strategy.position_size) in study script. Please replace 'study' with 'strategy'.
Script 'Error example' has been saved
这个尝试同样会失败,因为指标脚本无法访问策略的持仓规模变量(strategy.position_size)。遗憾的是,由于策略脚本本身不能生成警报,这个问题目前是无解的。我们无法在TradingView中实现基于策略持仓来触发警报的功能。
总结
在TradingView中,脚本分为两种类型:指标和策略。指标通常用于绘制数据、标记图形符号和生成警报。而策略除了拥有指标的所有功能外,还可以提交订单和管理市场头寸。
尽管两者的编码过程非常相似,但它们并非完全相同。’can’t use strategy functions in study script’这个错误就揭示了它们的区别。当我们试图在指标脚本中使用专属于策略的函数或变量时,这个错误就会发生。
修复这个错误有两种方法:一是将有问题的策略代码从指标中移除;二是将整个脚本的类型从指标改为策略,从而获得访问这些策略专属功能的权限。
如何修复TradingView策略中的”订单限额已达”错误?
在回测策略时,会产生大量的订单活动:开仓、平仓以及加仓订单。这在通常情况下没有问题,但当我们执行的订单过多时,TradingView就会触发’order’s limit was reached’(达到订单数量上限)的错误。本文将探讨如何应对这个错误。
TradingView的’order’s limit reached’错误
TradingView的优势之一是其广泛的市场覆盖和丰富的数据。与其它平台相比,我们无需手动管理交易品种和下载数据,这使得在不同时间周期、时间段和市场条件下测试策略变得非常容易。
但一个包含大量历史数据的图表也可能带来一个意想不到的缺点:我们的策略可能会在这些K线上生成过多的订单。当这种情况发生时,TradingView便会触发其著名的’order’s limit was reached’错误。这个错误会出现在我们图表的顶部:
与其他TradingView错误相比,这个错误并不会在Pine编辑器的控制台窗口中显示任何消息。这意味着,图表上方的这条提示是我们能获得的全部线索。幸运的是,处理这个错误并不复杂。
处理已达到订单数量上限
这里有个坏消息:对于TradingView的’order’s limit was reached’错误,并没有真正的解决方案。这个错误仅仅是在我们的策略回测时提交了超过3,000个订单时便会发生。并且,这是一个TradingView平台的硬性限制,而非一个编程错误。
但我们可以通过对策略进行一些调整来处理这个错误。以下是当你遇到’order’s limit was reached’错误时可以尝试的一些方法。
首先,检查你的策略代码。是否存在某个错误,导致脚本发送了远超预期的订单?比如说,你本想交易一个30周期的EMA,却不小心写成了ta.ema(close, 3)而非ta.ema(close, 30)。修复这个错误是一个唾手可得的胜利,能大大降低遇到订单数量上限的可能性。
如果代码没有错误,那么你需要调整策略以减少其生成的订单数量。这里有一些值得尝试的事情:调低或完全禁用策略的pyramiding设置,这样每个多头或空头头寸就只有一个交易;添加一个时间过滤器,这样策略就不会回测图表上的所有价格K线(见下文示例);在更高的时间框架上运行策略,如果你在1分钟图上遇到了订单上限,可以考虑切换到3分钟或5分钟图;分别在只做多和只做空的回测中测试策略的表现,这样通常可以将策略的订单数量减少一半;让你的策略只在一天中的某个特定时间段内提交订单,如果你计划手动执行该策略,那么在半夜发生的信号可以安全地跳过。
如果以上几点都不起作用或不适合你的策略,那么你将不幸地需要进行重大的策略调整。这意味着你需要重新审视你最初的策略思想,并设计出一个交易活动更少的策略,以便TradingView能够对其进行回测。
请注意,strategy.entry()、strategy.exit()和strategy.order()函数提交的都是订单(order)。但这与头寸(position)是不同的。毕竟,一个多头或空头头寸可能由多笔入场和/或出场订单构成。由于’order’s limit was reached’错误针对的是订单而非头寸,当我们的策略脚本为每个信号只使用一笔入场和一笔平仓订单时,它便能回测最多的信号。因此,如果我们为每个头寸使用5笔入场和5笔出场订单,我们只能回测200个信号。但如果只用一笔订单入场和出场,我们的策略便能测试1,000个信号。
现在,让我们探讨一些代码示例。每个示例都展示了我们如何能绕过’order’s limit was reached’错误。但请注意,每个策略、品种和时间框架都是独特的:对一个策略有效的方法,可能对另一个无效。
错误示例:由金字塔式加仓触发的订单上限
在TradingView中,编写一个进行金字塔式加仓的交易策略很容易:只需将pyramiding参数添加到strategy()函数中,或手动启用相应的策略选项。不幸的是,因此而触发’order’s limit was reached’错误也相当容易。
这里有一个例子:
//@version=5
strategy(title="错误示例", overlay=true, pyramiding=10)
// 计算数值
highestClose = ta.highest(close, 3)[1]
lowestClose = ta.lowest(close, 3)[1]
// 交易条件
enterLong = close > highestClose and close > open
enterShort = close < lowestClose and close < open
// 绘制数值
plot(highestClose, color=color.green)
plot(lowestClose, color=color.red)
// 提交订单
if enterLong
strategy.entry("EL", strategy.long)
if enterShort
strategy.entry("ES", strategy.short)
这个示例策略允许最多10次的金字塔式加仓。其开仓逻辑基于3周期内的最高或最低收盘价。这意味着策略的交易信号会非常频繁,产生的订单数量巨大,多到超出了TradingView平台的承受范围,因此会触发’order’s limit was reached’(达到订单数量上限)的错误。
然而,修复这个错误会更棘手一些。我们可以修改入场条件来降低交易频率,但这会改变我们策略的核心假设。我们也可以限制回测的时间窗口,但鉴于这个策略如此活跃,我们最终可能会得到一个因周期过短而缺乏统计意义的回测。
一个更实际的选择是暂时禁用金字塔式加仓。我们可能并不需要10次入场来仅仅验证一个初始信号是否有效。如果我们先在不加仓的情况下测试策略,若回测结果显示有潜力,我们随时可以再开启加仓功能,并在一个较小的时间窗口内进行更精细的测试。
因此,要修复’order’s limit was reached’错误,一个可行的方法是从 strategy() 函数中移除 pyramiding 参数。这样,示例中策略函数的声明(第2行)就变成了:
strategy(title="错误示例", overlay=true)
错误示例:通过时间过滤器修复订单限制错误
‘order’s limit was reached’错误的根源在于图表上的订单总数过多。但TradingView默认会在所有可用的历史数据上进行回测。由于我们无法在策略设置中直接配置回测的时间段,因此我们必须探索其他能以编程方式限制回测窗口的方法。
让我们通过下面这个会引发错误的策略脚本来看看如何着手:
//@version=5
strategy(title="错误示例", overlay=true)
// 计算数值
highestClose = ta.highest(close, 2)[1]
lowestClose = ta.lowest(close, 2)[1]
// 交易条件
enterLong = close > highestClose and close > open
enterShort = close < lowestClose and close < open
// 提交订单
if enterLong
strategy.entry("EL", strategy.long)
if enterShort
strategy.entry("ES", strategy.short)
这个策略所生成的’order’s limit was reached’错误,其中一个修复方法是使用一个程序化的时间过滤器。通过限制策略何时生成交易,我们便能限制它在整个回测期间的交易频率。
这个解决方案的挑战在于,如何设计一个好的时间过滤器。我们不想过度地限制我们的策略:如果只在一个很小的时间窗口上进行回测,我们便无法判断这个策略思想是否真的有效。我们也不能随意地排除任何时间段:如果我们最终将熊市行情排除在外,那么策略的回测结果也同样不可信。
但在现实中,一个时间过滤器有时必须排除大量的数据,才能防止TradingView的’order’s limit was reached’错误。前文的示例策略在1分钟图表上就非常活跃,以至于只有下面这样的时间过滤器才起作用:
// 交易条件
timeFilter = year == 2018 and
month >= 7 and
dayofmonth > 18
enterLong = close > highestClose and
close > open and
timeFilter
enterShort = close < lowestClose and
close < open and
timeFilter
我们在这里创建的timeFilter布尔变量,它只在K线的日期处于2018年7月19日及之后时才为true。我们将这个过滤器作为附加条件加入到enterLong和enterShort变量中。这些变量正是策略用来确定是否应该发送订单的依据。
顺便提一下,在我编写这个例子时,日期是2018年7月26日。这意味着这个交易策略在1分钟的EUR/USD图表上是如此活跃,以至于它连一周的数据都无法完整回测,就会遇到’order’s limit was reached’的错误。
幸运的是,并非所有策略都如此活跃。因此在很多情况下,一个时间过滤器是有效的。这里有一些我们可以尝试的其他过滤器示例:year == 2018 and month >= 7,只从2018年7月开始回测;year == 2018,只回测整个2018年;(year == 2017 and month > 6) and (year == 2018 and month < 7),回测从2017年7月到2018年6月底的时间段。
错误示例:通过改变策略逻辑修复订单限制错误
有时,即便我们关闭了金字塔式加仓,并大刀阔斧地限制了策略的时间窗口,我们仍然会遇到’order’s limit was reached’的错误。这对于那些在市场上进行高频交易的策略尤其如此。
那么该怎么办?嗯,那么绕过这个错误的唯一方法,就是改变策略的逻辑(可能再结合一个时间过滤器)。这也是最极端的选项,所以你可能想先尝试其他所有方法。但如果别无他法,我们将不得不让我们的策略去适应TradingView平台(而不是反过来让平台适应我们)。
假设我们有这个示例脚本:
//@version=5
strategy(title="错误示例", overlay=true)
// 计算数值
highestClose = ta.highest(close, 3)[1]
lowestClose = ta.lowest(close, 3)[1]
// 交易条件
enterLong = close > highestClose and close > open
enterShort = close < lowestClose and close < open
// 提交订单
if enterLong
strategy.entry("EL", strategy.long)
if enterShort
strategy.entry("ES", strategy.short)
让TradingView快速触发’order’s limit was reached’错误的原因,是这个策略的交易活动性:它基于3周期的最高和最低值来进入头寸。
要修复该错误,我们需要让我们的策略不那么活跃。一种方法是增加它在开新仓前的观察周期。比如说,我们将最高和最低收盘价的周期从3根K线增加到5根,像这样:
// 计算数值
highestClose = ta.highest(close, 5)[1]
lowestClose = ta.lowest(close, 5)[1]
这个策略之所以会迅速触发’order’s limit was reached’的错误,原因在于其交易逻辑过于活跃:它基于极短的3周期最高价和最低价来开立仓位。要修复这个错误,我们需要让策略的交易频率降低。一种方法是增加其开立新仓位前的回顾周期,比如将计算最高和最低收盘价的周期从3根K线延长到5根K线:
// 计算值
highestClose = ta.highest(close, 5)[1]
lowestClose = ta.lowest(close, 5)[1]
对于我在1分钟EUR/USD图表上的测试,仅仅这个改动就足以规避’order’s limit was reached’的错误。虽然这确实意味着我修改了策略的原始逻辑,但至少它现在可以在平台上运行和评估了。
总结
当我们的TradingView策略生成的订单总数超过3,000个时,就会发生’order’s limit was reached’的错误。不幸的是,这个错误标志着一个TradingView平台的内在限制,这意味着我们需要主动地去规避它,而不是试图修复它。
有几种方法可以应对这个错误。最好的情况是,策略的过度交易是由一个简单的编码错误导致的。如果我们的策略代码是正确的,那么我们就需要考虑其他方法来处理这个错误。
我们可以禁用金字塔式加仓,这样策略仍然会响应相同的交易信号,但订单数量会大大减少。或者,我们可以添加一个时间过滤器,让策略不要在图表的整个历史数据上进行回测。另一个选项是在一个稍高的时间框架上进行回测。如果以上这些方法都没有真正的帮助,那我们就需要回到原点,重新思考如何能在降低交易频率的前提下,仍然有效地测试我们的策略思想。
哪些服务可以自动化TradingView交易?
目前,TradingView本身并不支持自动交易。但随着自动交易和TradingView的流行,一些第三方公司加入进来,为TradingView提供自动交易功能。
它们是通过TradingView的警报实现的。当我们生成包含特定消息的警报时,第三方服务可以读取该警报信息,并用它来执行真实交易。
那么TradingView有哪些警报自动化服务呢?让我们来看看。
警报自动化服务列表(按字母排序)
这些第三方提供商提供在TradingView上实现交易自动化的工具和服务:3Commas、Aleeert、Alertatron、Altredo InteractiveBrokers插件、APIBridge、Autoview、Capitalise.ai、Cornix、Cryptohopper、Cryptowatch、Cwebhook、Gunbot、Mudrex、NextLevelbot、ProfitView、Quadency、SignalStack、Tickerly、Traderelay、TradersPost、TradingConnector、TradingView to MT4、TradingView.to、Wunderbit。
上面的列表包含了我经过广泛研究后找到的所有第三方,但仍然可能有所遗漏。如果你知道其中没有提到的服务,欢迎反馈,以便更新这篇文章供其他读者参考。
警报自动化服务提供的资产类别
并非所有上述提供商都覆盖所有类型的资产。事实上,大多数提供商只专注于加密货币。
以下是各家第三方提供的资产类别:
| 警报自动化服务 | 提供的资产类别 |
|---|---|
| 3Commas | 加密货币现货、期货、保证金和期权市场。 |
| Aleeert | 加密货币。 |
| Alertatron | 加密货币。 |
| Altredo InteractiveBrokers插件 | 股票、货币、期货、商品以及InteractiveBrokers支持的更多资产类别。 |
| APIBridge | InteractiveBrokers和各种印度经纪商。 |
| Autoview | 加密货币和外汇。此外,还可以通过OANDA的差价合约交易商品、指数和股票。 |
| Capitalise.ai | 多资产经纪商(如InteractiveBrokers)、差价合约经纪商(如Pepperstone和FXCM)以及加密货币(币安)。 |
| Cornix | 加密货币。 |
| Cryptohopper | 加密货币。 |
| Cryptowatch | 加密货币。 |
| Cwebhook | 任何提供cTrader软件的CFD经纪商所支持的品种。 |
| Gunbot | 加密货币。 |
| Mudrex | 加密货币现货和永续期货市场。 |
| NextLevelbot | 期货、股票、差价合约和加密货币(主要针对印度市场)。 |
| ProfitView | 加密货币现货、期货和保证金市场。此外,还可以通过OANDA的差价合约交易大宗商品、指数和股票。 |
| Quadency | 加密货币现货市场。 |
| SignalStack | 多资产经纪商(例如InteractiveBrokers和TradeStation)、CFD经纪商(例如OANDA)、期货经纪商(Optimus和NinjaTrader)以及加密货币(ByBit、Coinbase等)。 |
| Tickerly | 加密货币现货、期货和保证金市场。以及通过OANDA进行外汇、指数、商品、债券和加密货币交易。 |
| Traderelay | 通过币安交易加密货币现货、期货和保证金市场。此外,还可通过盈透证券交易股票、外汇、期货和差价合约。 |
| TradersPost | 股票、期权、ETF和加密货币。 |
| TradingConnector | 通过MetaTrader进行外汇、指数和商品交易。 |
| TradingView to MT4 | 理论上MetaTrader经纪商支持的所有资产类别,但官方没有明确说明。 |
| TradingView.to | 加密货币现货、期货和保证金市场。此外,还有二元期权、外汇以及MetaTrader支持的其他资产类别。 |
| Wunderbit | 加密货币。 |
请注意,当你阅读本文时,一些提供商可能已经扩展了其服务范围。请查看那些看起来最有前景的提供商,以确认他们目前可以处理哪些资产类别和交易所。
上面的表格和列表中还缺少几个第三方。截至撰写本文时,他们的网站已经下线。
被排除的提供商包括:
| 警报自动化服务 | 提供资产类别吗? |
|---|---|
| Auto4Mex | 未知;撰写本文时网站处于离线状态。 |
| Signalbot | 未知;撰写本文时网站处于离线状态。 |
| Superorder | 未知;撰写本文时网站处于离线状态。 |







