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

Pine Script(212):策略如何处理数据与订单成交

#Pine Script入门教学

策略脚本如何处理实时和历史数据

在策略能够发送任何订单之前,我们的策略脚本必须先进行计算。没有脚本的计算,策略就无法提交订单或执行任何其他操作。但TradingView脚本究竟在何时以及如何进行计算呢?让我们一探究竟。

TradingView策略脚本可以执行多种任务,例如提交订单、绘制数值、为图表背景上色等。但要执行这些操作,脚本必须先进行计算。只有当脚本处理价格数据后,它才能做出决策并采取行动。

TradingView策略的计算方式和时机,取决于它所处理的数据类型:是历史数据还是实时数据。下面我们来深入探讨。

策略如何处理历史数据

当我们将一个TradingView策略加载到图表上时,它会开始处理图表上的历史K线。在我们更改图表的时间周期、切换到其他交易品种或在浏览器中(重新)加载TradingView时,同样会触发这一过程。

通过遍历所有可用的历史K线,策略得以完成其历史回测。以下是策略处理历史K线的基本流程:

  1. 确定所需K线数量:TradingView首先会预估策略进行计算所需要的最少K线数量。这个数量取决于脚本代码中指标的周期长度:
    • 如果我们使用一个7周期的RSI进行交易,那么策略会在图表加载到第7根历史K线时,才首次进行计算。
    • 如果我们的交易逻辑基于30周期和75周期移动平均线的交叉,那么策略会等到第75根K线出现后才开始计算。
    • 在特殊情况下,我们可以通过 strategy() 函数的 max_bars_back 参数来手动指定这个回溯的K线数量,但这通常仅在TradingView无法自动从代码中推断出所需K线数量时才需要。
  2. 首次计算:在加载了足够多的历史数据后,策略会在第一根满足条件的K线的收盘时进行首次计算。在计算过程中,TradingView会执行我们的脚本代码,并触发其中编写的各种操作。
  3. 逐根K线计算:随后,策略会前进到下一根K线,并在其收盘时再次进行计算。
  4. 完成回测:这个每根K线收盘时计算一次的过程会一直持续,直到策略处理完图表上所有可用的历史K线。

注意:一个策略能够处理的历史K线总数取决于用户的TradingView账户类型:免费用户最多5000根,付费用户最多10000根。当然,这也取决于TradingView是否有足够的历史数据来生成这么多K线。

更精确地说,TradingView在处理每一根历史K线时遵循以下规则:

  • 策略在每根历史K线上只计算一次,这个计算发生在K线的收盘时。这意味着,在历史回测中,脚本进行计算时获取的当前价就是该K线的收盘价。
  • 由于计算是在K线已经收盘后进行的,所以脚本生成的所有动作(如开仓)也是在这根K线已经走完的背景下发生的。
  • 因此,当脚本在某一根历史K线上生成一个市价单时,该订单不会在该K线上成交,因为这根K线已经关闭,无法再进行交易。相反,这个市价单最早会在下一根K线的开盘时成交。
  • 在历史回测中,TradingView不会处理K线内部的价格波动。这是因为TradingView不会加载更低时间周期的数据,所以它无法窥探K线内部的走势。因此,它并不知道K线内部是先涨后跌还是先跌后涨,而是基于一些假设来模拟。

注意:如果我们启用了策略设置中的订单成交后重新计算(Recalculate After Order Filled),那么每当有订单成交时,脚本就会执行一次额外的计算。这个额外的K线内计算在历史回测中也会发生,但它仅能使用该K线的开盘价、最高价、最低价和收盘价这四个价格点。这个选项可以让策略的响应稍微快一些。但是,TradingView仍然需要猜测K线内部是先触及高点还是低点,所以从这个角度看,历史回测的根本机制并未改变。

当图表上最后一根历史K线处理完毕后,历史回测就完成了。此时,我们可以查看策略表现报告,或者在图表上滚动查看策略在过去是如何执行交易的。

接下来有两种可能:

  • 如果当前市场处于休市状态,那么回测结束后,策略将停止运行。
  • 如果策略所应用的交易品种正在活跃交易中,那么在完成历史回测后,TradingView会开始使用实时传入的数据来继续运行策略。

接下来,我们看看策略是如何处理实时数据的。

策略如何处理实时数据

当TradingView策略在实时数据上运行时,其默认的计算方式与历史回测相同:每根K线计算一次,在K线收盘时进行。

但与历史数据处理相比,有一个至关重要的区别:在处理实时数据时,TradingView不再需要猜测K线内部的价格走势。它可以直接观察到价格的实时变化,从而准确地知道是先触及高点还是先触及低点。这意味着我们的止损单和限价单能够以正确的顺序和更接近真实情况的方式被执行。

此外,还有两个可选的设置会带来显著的不同:

  • 在每个Tick上重新计算(Recalculate On Every Tick):这个设置会使策略在每一次价格变动(Tick)时都重新计算。这让策略变得极为灵敏和活跃,但同时也使其计算模式与历史回测完全不同。因此,一旦我们启用此设置,策略的历史回测结果就失去了参考价值。我们必须通过前向测试(模拟盘或实盘)来评估策略的真实表现。
  • 订单成交后重新计算(Recalculate After Order Filled):启用此设置后,每当有订单成交,脚本就会立即进行一次额外的计算。这个计算发生在K线内部,使用的是成交那一刻的真实价格。利用这个选项,我们可以在市价单成交后,立即为其提交止损和止盈订单。

总结

TradingView策略脚本的计算方式和时机取决于其处理的价格数据类型。

对于历史数据,策略会逐根K线进行处理。每根K线只在收盘时进行一次计算。脚本所采取的任何行动都是基于这个K线已收盘的背景。因此,市价单最早也只能在下一根K线的开盘价成交。

当处理完所有可用的历史K线后,策略要么结束运行,要么切换到实时数据处理模式。

对于实时数据,策略默认的计算方式仍然是每根K线收盘时计算一次。但此时,TradingView能够获取到K线内部的真实价格波动。此外,通过启用在每个Tick上重新计算设置,我们可以让策略响应每一次价格更新。这个设置能极大地提升策略的响应速度,但其代价是:我们必须放弃其历史回测的表现,因为回测结果是在每根K线计算一次的模式下得出的,与实时运行模式完全不同。

策略订单如何以及何时成交

当TradingView回测一个交易策略时,它必须判断哪些订单会被成交,以及它们成交的先后顺序。但在这个过程中,TradingView究竟做了哪些假设?真实交易中的订单成交又是如何被模拟的?让我们一探究竟。

大多数TradingView的文章都侧重于如何编写代码来完成特定任务。但了解TradingView幕后的运作机制与编写代码本身同等重要。其中一个关键主题就是TradingView如何模拟订单成交。

正如我们之前讨论过的,一个策略在历史数据和实时数据上的行为可能有所不同。在历史数据上,每根K线只计算一次,任何生成的订单最早也要在下一根K线上才能成交。而在实时数据上,我们可以选择让策略进行更频繁的计算。

但实时数据与历史数据之间的差异不仅影响策略的行为逻辑,也深刻影响着TradingView判断订单是否成交的方式。让我们来深入了解。

TradingView如何在历史数据上模拟订单

当一个策略脚本在历史数据上进行计算时,TradingView面临一个固有的局限:它无法看到K线内部的价格是如何波动的,也无法获取真实的交易历史。它所拥有的全部信息只有这根K线的开、高、低、收(OHLC)四个价格。

因此,TradingView并不知道这根K线内的价格在现实中是如何运动的。是最高价先出现,还是最低价先出现?TradingView无从知晓。

那么,TradingView是如何解决这个问题的呢?它基于一些合理的假设来推断K线内部价格可能的运动轨迹。尽管这些假设合乎逻辑,但终究只是有根据的猜测。

利用历史K线的四个价格点,TradingView对K线内部价格的实时运动路径做出了以下假设:

  • 当开盘价更接近最高价时:TradingView认为价格是先向上运动触及最高价,然后再向下运动触及最低价。所以它假设的路径是:开盘价 → 最高价 → 最低价 → 收盘价。
  • 当开盘价更接近最低价时:TradingView则假设价格是先向下运动触及最低价,然后再向上运动触及最高价。它假设的路径是:开盘价 → 最低价 → 最高价 → 收盘价。

毫无疑问,这些假设对某些K线来说是准确的。但现实中,肯定也有很多K线的实际走势与TradingView的假设截然不同。

如果我们将TradingView的假设可视化,大概是这个样子:

在这张图中,左侧是实际的K线。中间是TradingView基于其假设所推断的K线内部路径。而右侧则展示了现实中可能发生的另外两种路径。可以看到,某些真实路径对交易结果的影响可能远比TradingView假设的要糟糕。

最大的问题当然是:这些假设对我们的策略回测结果有多大影响?不幸的是,没有一个确切的答案。但我们可以从逻辑上分析它的影响机制。

这些假设是否会影响我们的策略,关键在于我们同时挂出的未成交订单(挂单)数量:

  • 如果策略只有一个挂单(例如只有一个止损单),那么这些假设不会影响交易结果。
  • 如果策略有两个或更多的挂单,但只有一个挂单的价格落在了当前K线的价格范围内,那么这些假设也不会影响交易结果。
  • 但是,如果策略有两个或更多的挂单(例如一个止损单和一个止盈单),并且它们的价格都落在了当前K线的价格范围内,那么交易的最终结果就完全取决于TradingView的路径假设了。

为了让最后一种情况更具体,假设我们的策略持有一个多头仓位,并同时挂出了一个止损单和一个止盈限价单,且这两个订单的触发价都在某一根历史K线的最高价和最低价之间。现在,可能发生两种情况:

  • 如果TradingView假设价格路径是开盘价 → 最高价 → 最低价,那么我们的止盈限价单会先被触发,这笔交易将盈利。
  • 如果TradingView假设价格路径是开盘价 → 最低价 → 最高价,那么我们的止损单会先被触发,这笔交易将亏损。

不幸的是,我们无法改变TradingView的这些历史回测假设。我们能做的,就是对回测结果保持一份理性的审视,并善用策略设置中的滑点和限价单验证功能(下文会讨论)。

除了对K线内部路径的猜测,TradingView在回测时还做了另外两个重要假设:

  • 无限流动性:在回测中,TradingView假设K线最高价和最低价范围内的任何价格点都存在足够的流动性可以成交。
  • 无视成交量:TradingView不考虑订单大小。无论你的订单量有多大,它都假设可以被市场完全成交。

和所有假设一样,这些猜测在某些情况下是不成立的。例如,在回测低流动性的交易品种时,策略可能会成交一个远大于该K线总成交量的订单——这在真实交易中,若没有巨大的滑点是不可能发生的。

TradingView也忽略了K线内部可能存在的价格真空区(跳价)。但在交易低流动性品种,或在重要新闻发布时,K线内部的很多价格点上可能根本没有任何交易。

这些假设还带来一个更微妙的后果:由于每个价位都被认为可以成交,这导致订单在历史回测中可能会在K线的精确最高价或最低价成交,而这在真实交易中是极小概率事件。即使是在日线开盘价成交,也往往过于乐观。

幸运的是,我们有两个策略设置可以帮助我们缓解这些乐观假设带来的影响:

  • 滑点(Slippage):通过设置滑点,市价单和停止单会以一个对我们更不利的价格成交。这可以模拟真实市场中流动性不足的情况,并避免订单在理想的开、高、低、收价格点上成交。
  • 限价单价格验证(Verify Price For Limit Orders):启用此设置后,限价单只有在价格穿过其指定价位一定点数后才会被认为成交。这使得历史回测中的限价单成交更接近真实情况,也有效避免了订单在精确的最高或最低价成交。(注意:此设置只验证成交条件,不改变成交价格。)

现在,让我们看看TradingView在实时数据上是如何模拟订单的。

TradingView如何在实时数据上模拟订单成交

当我们的策略脚本在实时价格上运行时,TradingView可以获取到更详细的数据来模拟订单成交。它不再需要猜测K线内部的价格路径。相反,它会根据价格在实时中实际发生的顺序来模拟订单成交。

尽管如此,在实时数据模拟中,仍然存在一些假设:

  • 市价单:当策略发送一个市价单时,TradingView会模拟在下一个收到的报价(tick)上成交。但在真实交易中,尤其是在低流动性或高波动性的市场中,我们最终的成交价可能会更差。
  • 限价单:当策略发送一个限价单时,只要有一个实时报价触及了限价,TradingView就会认为订单成交。这乐观地假设了我们的订单排在订单簿的最前面。实际上,价格往往需要在限价位停留或交易一段时间后,我们的订单才能成交。
  • 停止单:当策略发送一个停止单时,只要有一个价格更新触及了订单价格,TradingView就会认为订单成交。这假设了在该价格点没有滑点,且有足够的流动性。

注意:当我们通过真实的经纪商账户来运行我们的策略脚本时,订单的成交价格将完全取决于经纪商实际执行的价格。

这些实时模拟的假设所带来的影响,远小于历史回测中的假设。这使得前向测试(forward test)比回测更具参考价值。但我们仍需牢记,实时测试中看到的模拟成交价,不一定与我们用真金白银交易时的价格完全相同。(你仍然可以通过设置滑点和限价单价格验证来让模拟成交结果更保守一些。)

总结

TradingView策略如何模拟订单成交,取决于脚本所使用的数据类型。

  • 在历史K线上,TradingView无法看到K线内部的波动,因此必须对价格路径做出假设。当开盘价靠近最高价时,它假设路径为开→高→低→收;当开盘价靠近最低价时,它假设为开→低→高→收。当策略同时挂有多个可能在同一根K线内成交的订单时(如止盈和止损),这些假设将直接决定回测的交易结果是盈利还是亏损。此外,回测还假设了无限的流动性和任意价格的可成交性,这在波动剧烈或流动性差的市场中会严重高估策略表现。
  • 在实时数据上,TradingView可以获取到真实的报价流,因此可以减少很多猜测。但它仍然乐观地假设市价单和停止单没有滑点,限价单无需排队。这使得前向测试的结果仍然会比真实交易略显乐观。

为了让回测更接近现实,强烈建议始终使用策略设置中的滑点(Slippage)和限价单价格验证(Verify Price For Limit Orders)功能。

赞(0)
未经允许不得转载:图道交易 » Pine Script(212):策略如何处理数据与订单成交
分享到

评论 抢沙发

登录

找回密码

注册