写一份指标公式时不会感觉到负担,装上几十份之后,切换周期开始变慢、翻页出现等待、条件预警的刷新也跟着拖。这几件事的共同来源是同一个:单次求值要算多少东西。通达信公式优化计算量,改的不是表达式表达的结论,而是它算出这个结论所走的路径。

下面按五个切入点展开,每个切入点都给出改前改后的写法对照,以及一个可以观察的验证方法。文中的函数名与菜单项以通达信金融终端个人版为准。全文只讨论求值路径的开销,不涉及任何标的的判断。

一、先把「慢」落到一个可观察的量上

「公式太重」不是一个可以直接核对的描述。先把它换成一个能测的量,后续的改动才有比较对象。

可观察的量 怎么取
单只标的单次求值耗时 用一份极简公式做对照,逐步加回原公式的语句
切换周期后的出图等待 在同一个品种上反复切换周期间隔,观察等待时间
同一批公式的加载时间 把公式从图上卸下再挂上,对比前后

选其中一个作为基线,改动之后用同一个量复测。三个量之间的数值不必互相比,各自和自己的基线比才有效。比较时把当时的品种、周期与公式数量一起记下来,否则前后两次的测量对象可能不是同一件事。

二、切入点一:往回取值的窗口长度

通达信公式优化计算量里见效最直接的一项,是把往回取值的窗口收短。取数窗口写多长,每次求值就要覆盖多长的历史区间。

{ 改前:窗口 250 根,且同一量算了两遍 }
高:HHV(H,250);
低:LLV(L,250);
位置:(C-低)/(高-低);

{ 改后:窗口收到实际需要的长度,中间量复用 }
N:=60;
高:=HHV(H,N);
低:=LLV(L,N);
位置:(C-低)/(高-低);

两段写法给出的曲线形态会不同,因为它们看的历史区间不一样。这不是同一份逻辑的两种写法,而是两种设定。真正要确认的是:原公式里的窗口长度是不是必要的。若某个窗口长度只是取了个整数,收短到实际需要的长度就能省掉一段计算。

收窗口这件事有一个前提:间隔的取值要写进公式,不能靠改动时的临时判断。把窗口长度放到参数表里,之后调整只要改一个数值,不必进编辑器改正文。

三、切入点二:重复计算的中间量

同一段表达式在正文里出现多次,每次出现都会重新求值一遍。把重复的部分定义成中间量,之后引用变量名,求值路径就只走一次。

写法 求值次数
同一表达式在正文里出现三次 三次
定义为中间量后被引用三次 一次

中间量用 := 定义。这一项改动不影响结果,是纯收益:表达的含义不变,图上画出来的东西不变,只是算的次数少了。公式越长,这一项的收益越明显。

{ 改前:同一段均线差被算了三遍 }
条件A:EMA(C,12)-EMA(C,26)>0;
条件B:EMA(C,12)-EMA(C,26)>REF(EMA(C,12)-EMA(C,26),1);
条件C:ABS(EMA(C,12)-EMA(C,26))>0.1;

{ 改后:算一遍,后面引用名字 }
差:=EMA(C,12)-EMA(C,26);
条件A:差>0;
条件B:差>REF(差,1);
条件C:ABS(差)>0.1;

两段写法在数值上完全等价,差别只在求值次数。整理公式时,把重复出现的表达式挑出来命名,是改动成本低而效果明确的一项。

四、切入点三:参与扫描的品种范围

条件预警与条件选股会对一批品种逐个求值。单次求值的耗时乘以品种数,构成这一项的总开销。品种数这一项的调节方式不在公式里,而在范围设置里。

  • 全市场范围。品种数由市场容量决定,单次求值慢的公式在这个范围下负担明显。
  • 自选清单。品种数由清单长度决定,是最容易收窄的一项。
  • 板块范围。品种数由板块成分决定,成分变动会带来范围波动。

范围里的停牌品种与当日无行情的品种同样会进入扫描队列。它们的求值结果没有意义,扫描动作本身仍然发生。把自选清单逐项清理一遍,比在公式里加过滤条件更直接。

范围还会影响预警的轮询表现。范围大、单轮算得久时,两个轮询点之间的实际间隔会被拉长,看起来像是提示变慢了。这一项与公式瘦身是两件事,改完公式之后要单独复测范围这一侧。

五、切入点四:跨周期引用与深层回溯

通达信公式优化计算量在跨周期这一项上,开销来自周期对应。在较短周期上引用较长周期的数据时,求值要在两种周期之间建立一次对应关系,路径比同周期引用长。

{ 同一周期内的回溯,路径较短 }
A:=REF(C,1);

{ 引用较长周期的数据,需要做周期对应 }
B:="MACD.MACD";

深层回溯是同一类问题的另一种表现。REF 的层数越深、与整段历史相关的函数用得越多,单次求值要覆盖的范围就越长。核对的办法是把这类语句单独拎出来测一遍,看它对总耗时贡献多少;贡献大的再考虑是否有等价的短路径写法。

跨周期引用还有一个连带影响:它依赖被引用周期的数据存在。T0002 目录下缺少对应周期的本地数据时,引用的那一句取不到值,公式要么显示为空,要么退回一个默认值。这类情况属于数据侧的问题,不在计算量优化的范围内,排查时要分开处理。

六、切入点五:绘图与输出语句的开销

输出语句数量有上限,超限时编译会直接报错。在没超限的情况下,绘图语句仍然会带来开销:每一根 K 线上都要判断条件是否成立,成立时还要完成一次绘制动作。

语句 开销来源
曲线输出 逐根 K 线保留一个数值
STICKLINE 类柱体绘制 逐根判断条件并完成填充
DRAWTEXT 类标注 逐根判断条件并完成文字绘制

绘图语句与计算语句要分开看待。把整段历史都铺满标注,与只在当前这根 K 线上做一次标注,两者的开销不同。后面那种写法用 ISLASTBAR 把绘图条件限制住,正文逻辑完全不变,只是绘图发生的次数少了。

中间量不参与绘图,输出语句参与。把只用于计算、不需要画出来的步骤全部改成 := 定义的中间量,是最直接的一项调整。

七、改动之后怎么确认真的变快了

五项改动做完,要用第一节选定的那个基线复测一遍。复测的方式与取基线时保持一致,否则前后两个数字不可比。

{ 复测用的对照公式:只保留最少的求值动作 }
对照:MA(C,5);

把对照公式与改后的公式分别挂到同一个品种上,反复切换周期,观察等待时间的差别。差别不明显时,说明瓶颈不在公式的求值路径上,而在数据读取或绘图通道上,继续改公式不会有收益。

那如果五项都改过,单只标的的求值时间确实降下来了,而整批扫描的等待时间几乎没变,问题出在哪儿?范围收紧与公式瘦身是两件独立的事,前者调的是品种数,后者调的是单次路径。两者之中哪一项在总开销里占的份量大,决定了下一步该动哪一个。

通达信公式优化计算量这件事没有一步到位的做法,可取的方式是先把「慢」落到一个可测量的量上,再按五个切入点逐项试,每改一项复测一次。本文只讲求值路径的开销构成与改写方向,不涉及具体标的的判断,也不涉及预警时点的测量方法,后者见站内另一篇讲分段测量的条目。另有 公式报错与卡顿排查 里讲编译提示与其它故障的条目、指标原理与参数 里讲参数取值与计算路径的条目、公式编写教程 里讲函数与语句结构的条目,可对照查看。

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。