HighestFC(Numeric Price,Numeric Length)
说明:
计算指定周期内的数值型序列值的最高值(快速计算版本)。特别注意:在同一个策略代码的函数调用中,length参数不能改变,否则会引起计算错误。
在一个单元(程序+商品)中,这个函数只能出现1次,而且必须不能再if /else逻辑中,否则会出现不可预测错误?
AverageFC也是这样吗?
不是只能出现一次
是length这个参数,不能一会儿是20,一会儿是100.
同一个代码位置的length,数值不可以变动
这个问题很有意思,一般情况下,常常发生在以下3个条件满足的情况下:
1.【主策略应用s】调用了【用户函数f】
2.【主策略应用s】调用【用户函数f】的场所,发生在【主策略应用】的If、Else、While、For的【条件判断】或者【分支、循环体内部】
3.【用户函数】内部定义了【序列类型的变量】:比如函数的形参定义为序列变量、或函数内部变量定义为序列变量
原因:要搞清楚为啥会引起错误的原因。
首先,要深刻理解【序列类型变量】与【普通类型变量】的不同点。外观直觉上很容易理解的是:【序列变量】可以以Bar的序列号码进行【回溯取值】,正数是针对当下Bar向历史Bar回溯取值,负数是针对当下Bar的未来Bar回溯取值。
然后,【普通变量】就只能取到当下Bar计算得到的值,其他Bar上的计算过的值是无法取到的。所以从计算机高级语言对于变量生命期的角度来讲,【普通变量】其实就是【局部变量】,其数值的有效期就在【当下OnBar的一对花括号{}内部有效】,【OnBar】执行完毕后,操作系统会自动回收、释放【普通变量】的内存空间,换句话说,执行完一次【OnBar】后【普通变量】就消失了,灰飞烟灭了,下一次【OnBar】来临的时候,【普通变量】又从初始化状态开始重新计算或被重新赋值开始。
【序列变量】是TB自己构造的金融序列数据属性的一种特殊变量。首先从可以回溯的特性,我们可以反推出来,这类变量的生命周期,肯定不是执行1次【OnBar】就被操作系统释放了,而是一直存在于【内存】中,而且以【Bar】为单位分配【内存空间】给【序列变量】,这样才能满足像数组一样通过下标向前向后进行回溯取值。
虽然【序列变量】分配的【内存空间】数量是按照Bar数逐一分配,并且生命期就像Global一样一直有效,不会被操作系统释放。但是【序列变量的数值】却是会受到【TB后台】的影响,这一点对于你的【策略代码】是无感知的,TB官方在介绍【序列变量】特性的时候,常常会介绍【继承性】【可回溯性】,【可回溯性】比较容易理解,因为分配的空间一直有效且存在。但是【继承性】却是受控于TB后台程序管理的,并且因为实盘与回测对于【OnBar】的机制不同,序列变量的【继承性】会导致的本次【OnBar】执行完后,下一次【OnBar】执行前TB后台会【自动】把【序列变量值】变成【前根Bar最后一次执行完的序列变量计算结果值】开始,TB后台自动做得一次序列变量的数值复位。
【序列变量的继承性】:真是因为【序列变量的数值】会在【主策略程序以外】的地方,被TB后台【重置到前根Bar最后一次执行结果的数值】。所以需要变量特别是在实盘时的每一次【OnBar】一定要确保被执行计算一次,一旦某个Tick驱动的【OnBar】因为If、Else、While、For的【条件判断】或者【分支、循环体内部】的情况、条件不同,出现时而被执行、时而不被执行的时候,就会发生【不可预测错误】。
关于【序列变量】【继承性】【可回溯性】的知识点,你可以观看以下视频教程(20:48开始):
https://video.tbquant.net/video?id=video393
最后结合你提出的问题现象,因为【用户函数】内部使用的【序列变量】,但是【主策略应用】在调用【用户函数】的时候,调用场所在
(1)If、Else、While、For的【条件判断语句】:因为编译器优化时,导致调用【用户函数】的【逻辑条件】没有确保被执行到。换句话说,无法确保每个Tick、每根Bar都能执行【用户函数】
(2)If、Else、While、For的【分支、循环体内部】:因为【主策略应用】每个Tick或每根Bar只能执行其中一条分支路径,但是【用户函数】只存在于部分分支路径中被执行。所以,换句话说,无法确保每个Tick、每根Bar都能执行【用户函数】。
关于这个实际问题场景的讲解,以下视频特别有益处: