就写了简单的MACD,用来显示追日的MACD值:
Params
Numeric FastLength(12);
Numeric SlowLength(26);
Numeric MACDLength(9);
Vars
Defs
Numeric MACDDiff(Integer daysAgo)
{
return XAverage( CloseD(daysAgo), FastLength ) - XAverage( CloseD(daysAgo), SlowLength ) ;
}
Numeric MACDAvg(Integer daysAgo)
{
return XAverage(MACDDiff(daysAgo),MACDLength);
}
Numeric MACDValue(Integer daysAgo)
{
return 2 * (MACDDiff(daysAgo) - MACDAvg(daysAgo));
}
Events
OnBar(ArrayRef<Integer> indexs)
{
Range[0:DataSourceSize() - 1]
{
PlotAuto("MACD",MACDValue(1),0,Color9(),Enum_Bar);
//加上这句代码后,会改变前面的运行结果,不知何解?
if( MACDValue(0) > MACDValue(1)){ }
}
}
就一个简单的求昨日MACD值的代码,如果加上 if( MACDValue(0) > MACDValue(1)){ } 这句代码,显示的结果就是错的,如果注释这段代码,显示的结果就正确,我就不明白了,后面的代码还能改变前面的值?
这个问题困扰我好几天,寝食难安,请高手指点!
又是一个【序列变量】与【用户函数】嵌套调用的【天坑】问题。【MACDValue】这个函数是你自定义的函数虽然没有直接使用【序列类型变量】,但是里面嵌套调用了【MACDDiff】和【MACDAvg】这2个函数,虽然这2个函数也没有使用【序列类型变量】,但是它们都调用了系统内置的用户函数【XAverage】,你可以进一步打开【XAverage】(TB是开放这个函数的源代码的),这里就可以看到其实【XAverage】是定义了一个【序列类型的变量】Series<Numeric> XAvgValue,这还没完,好家伙你在调用【XAverage】前,还嵌套调用了【CloseD】这个系统内置的用户函数,同样方法你打开源代码可以发现内部定义了2个【序列变量】:Series<Numeric> barCnt; Series<Numeric> dayClose; 代码我就不再贴第2份了。
//------------------------------------------------------------------------
// 简称: XAverage
// 名称: 求指数平均
// 类别: 用户函数
// 类型: 内建函数
// 输出: 数值型
// 说明: 函数中使用了序列变量请不限制条件调用
//------------------------------------------------------------------------
Params
Numeric Price(10); //数值型序列值
Integer Length(10); //周期数
Vars
Numeric sFcactor;
Series<Numeric> XAvgValue;
Begin
sFcactor = 2 / ( Length + 1 );
if (CurrentBar == 0 )
{
XAvgValue = Price;
}else
{
XAvgValue = XAvgValue[1] + sFcactor * ( Price - XAvgValue[1] ) ;
}
Return XAvgValue;
End
至于为什么【用户函数】使用了【序列变量】后,在外部调用时,就会出现很多“天坑”问题,刚好昨天也回答过一个类似的问题: https://bbs.tbquant.net/thread/20250204220009584238
所以,如果你弄明白问题的原因后,接下就是怎么解决问题了,解决办法也很简单,只要确保MACDValue函数每次都一定会在【OnBar】主体被执行,不会被编译器优化,不会因为分支路径不满足而不被执行,以下就是在你的代码基础上稍微修改一下就可以解决问题了:
Params
Numeric FastLength(12);
Numeric SlowLength(26);
Numeric MACDLength(9);
Defs
Numeric MACDDiff(Integer daysAgo){
return XAverage( CloseD(daysAgo), FastLength ) - XAverage( CloseD(daysAgo), SlowLength ) ;
}
Numeric MACDAvg(Integer daysAgo){
return XAverage(MACDDiff(daysAgo),MACDLength);
}
Numeric MACDValue(Integer daysAgo){
return 2 * (MACDDiff(daysAgo) - MACDAvg(daysAgo));
}
Events
OnBar(ArrayRef<Integer> indexs){
Range[0: DataSourceSize - 1]{
//【建议】:把 MACDValue(1) 函数 从 PlotAuto 传参的地方抽出来,放到OnBar主体部分,确保没有执行OnBar都一定会被执行
//把内含序列变量的函数 抽调到【OnBar】主体部分执行,是一种好的习惯,可以减少出错的几率,特别是遇到 序列类型变量
Numeric n = MACDValue(1);
PlotAuto("MACD", n, 0, Color9(), Enum_Bar);
//把 MACDValue() 函数调用从 If的条件语句中抽出来,放到OnBar主体部分,确保没有执行OnBar都一定会被执行
Numeric n0 = MACDValue(0);
Numeric n1 = MACDValue(1);
If(n0 > n1){ }
}
}
CloseD的参数是一个回溯值,每一个调用,不能动态变化,要常量或不变的值,否则影响序列变量,因为CloseD里面有序列变量。
已经在关注了