变量跟踪是将程序化执行过程中使用的策略变量进行记录保存。通过记录关键点的数据可以完整的分析策略每次执行过程中的逻辑,有助于帮助用户在策略开发初期定位各种预期与执行结果不同等问题,同时降低调试分析的难度。

# 图表变量跟踪V6.3+

图表程序化启动变量跟踪的步骤如下图所示:

# 后台变量跟踪V6.3+

后台程序化启动变量跟踪的步骤如下图所示:

# 跟踪分析引导

我们以代码范例为切入点进行分析,以帮助大家快速掌握变量跟踪的使用技巧和注意事项。

字符串变量与条件判断中的变量

例1

MA1:=MA(CLOSE,5);
MA2:=MA(CLOSE,20);

//字符串变量
品种:STKLABEL;

if time=134600 then begin
//条件判断中的变量
    探针:=time;
end
1
2
3
4
5
6
7
8
9
10

输出结果:

> 2022-04-06 13:44:04.689    Time:2022.04.06 13:44:00 Close:4256.2 MA1:4254.560 MA2:4252.090 品种:1000000.000 探针:0.000 
> 2022-04-06 13:45:03.687    Time:2022.04.06 13:45:00 Close:4251.8 MA1:4254.520 MA2:4252.130 品种:1000000.000 探针:0.000  
> 2022-04-06 13:46:02.700    Time:2022.04.06 13:46:00 Close:4252.4 MA1:4254.240 MA2:4252.290 品种:1000000.000 探针:134600.000
> 2022-04-06 13:47:02.685    Time:2022.04.06 13:47:00 Close:4253.0 MA1:4253.720 MA2:4252.350 品种:1000000.000 探针:134600.000
1
2
3
4

分析详解

  1. 限制:不支持字符变量调试输出,如上所示变量'品种'输出的结果并非预期的品种名称而是100000。
  2. 限制:变量打印输出不受判断条件控制;无论条件是否满足,每次执行时所有变量都将被打印输出,等同于全局变量效果;如上所示,
    • 当time<134400时,条件不成立,但是变量名探针同样被打印输出,其结果是默认的初始值0,
    • 当time=134600时,条件成立,变量名探针的结果被修改成当前的time。
    • 当time>134600时,条件不成立,但是变量名探针依旧会被输出,结果为上次修改后的结果。
  3. 字符串、特定条件控制下输出结果请使用debugfile函数实现。
如何解决条件判断内的变量等同于全局变量效果的问题

在变量使用时,只需在判断体外,对普通变量进行声明赋初始值即可,如下范例第5行所示。等同于变量使用前显示声明,可以有效提供代码的规范和健壮性。

例2

MA1:=MA(CLOSE,5);
MA2:=MA(CLOSE,20);

//声明并赋初始值0
探针:=0;

//字符串变量
品种:STKLABEL;

if time=134600 then begin
//赋值操作
    探针:=time;
end
1
2
3
4
5
6
7
8
9
10
11
12
13

输出结果:

> 2022-04-06 13:44:04.689    Time:2022.04.06 13:44:00 Close:4256.2 MA1:4254.560 MA2:4252.090 探针:0.000 品种:1000000.000 
> 2022-04-06 13:45:03.687    Time:2022.04.06 13:45:00 Close:4251.8 MA1:4254.520 MA2:4252.130 探针:0.000 品种:1000000.000 
> 2022-04-06 13:46:02.700    Time:2022.04.06 13:46:00 Close:4252.4 MA1:4254.240 MA2:4252.290 探针:134600.000 品种:1000000.000 
> 2022-04-06 13:47:02.685    Time:2022.04.06 13:47:00 Close:4253.0 MA1:4253.720 MA2:4252.350 探针:0.000 品种:1000000.000 
1
2
3
4
变量存在多处赋值操作时,如何跟踪每个赋值节点时的结果

基于调试输出功能,我们可以在公式中增加多个临时变量,分别用于保存各个关键节点的结果。来实现逻辑跟踪,例如例3中,在执行过程中,close>MA1*0.8close>MA1*0.9存在同时满足的情况,这类条件关系有交集的逻辑错误问题按照例3的代码风格并不能体现出来,因为探针在条件都成立时,最终变量探针=2。
注:也可以结合debugfile函数完成逻辑调试跟踪问题。

例3

MA1:=MA(CLOSE,5);

//声明并赋初始值0
探针:=0;

if close>MA1*0.8 then begin
    探针:=1;
end

if close>MA1*0.9 then begin
    探针:=2;
end
1
2
3
4
5
6
7
8
9
10
11
12

我们可以针对性的调整代码编写风格,优先将关键条件结果采用变量形式存储,这样能够更好的结合变量调试功能进行高效的逻辑分析。将示例3调整后,如下所示:

MA1:=MA(CLOSE,5);

//声明并赋初始值0
探针:=0;

cond1:=close>MA1*0.8;
if cond1=1 then begin
    探针:=1;
end

cond2:=close>MA1*0.9;
if cond2=1 then begin
    探针:=2;
end
1
2
3
4
5
6
7
8
9
10
11
12
13
14

详解

  1. 通过cond1cond2的条件结果,可以判断if条件语句是否被执行,进而可以确定执行逻辑上的关系。

# 高级调试技巧

策略在开发过程中不可避免的需要跟踪调试,当系统提供的变量跟踪功能无法满足逻辑调试需求时,我们可以结合debugfile函数跟踪逻辑执行过程,以达到快速定位解决问题。

debugfile(文件保存路径,写入的文本内容,变量)

示例1:单个变量打印输出

//将在程式化交易的监控部分输出到D:\TEST.TXT文件, "当前资产为1234.00",
//"%.2f"为一个打印的控制符号,系统会将他替换为指定的一个数字输出,%.2f为显示两位小数,%.0f则表示不显示小数。
DEBUGFILE('D:\TEST.TXT','当前资产为%.2f',1234);
1
2
3

示例2:多个变量同时打印输出

//通过NUMTOSTR函数将多个数值分别转换成字符串后,使用'&' 将字符串拼接在一起即可。参数3位置可以填任意数值。
DEBUGFILE('D:\TEST.TXT','当前资产='&NUMTOSTR(TASSET,2) & '   当前持仓='&NUMTOSTR(THOLDING,0),1);
1
2

在调试过程中,一般都是采用示例2中的方式实现,dubugfile一般是就近原则,将其加在需要调试的逻辑条件附近。完整的调试示例如下:

//中间变量
ma5:ma(close,5);
ma20:ma(close,20);
 
//开仓语句
con1:=cross(ma5,ma20);  //金叉
con2:=cross(ma20,ma5);  //死叉

debugfile('D:\T_' & stklabel & '.txt',stklabel &'   [开仓条件='& numtostr(con1 and tholding=0,0)  &']'
        & '   各项条件:[开多条件1=' & numtostr(con1,0)&'   持仓手数='& numtostr(tholding,0)&']',0);
if con1 and tholding=0 then
    begin
         tbuy(1, 1, mkt);
   end

debugfile('D:\T_' & stklabel & '.txt',stklabel &'   [平仓条件='& numtostr(con1 and tholding=0,0)  &']'
        & '   各项条件:[平仓条件1='& numtostr(con2,0)&'   持仓手数=' & numtostr(tholding,0) & ']',0);
if con2 and tholding=0 then
    begin
         tsell(1, 1, mkt);
    end
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

第9行解析

  • 参数1:'D:\T_' & 'stklabel' & '.txt'
    • 日志写入的路径,此处的结构:'D:\T_' + 品种代码 + 文件名后缀。此处的品种代码是字符串变量,多品种时可以实现分别记录,避免混淆。
  • 参数2:
    'stklabel' & ' [开仓条件=' & numtostr(con1 and tholding=0,0) & ']' & ' 各项条件:[开多条件1=' & numtostr(con1,0) & ' 持仓手数=' & numtostr(tholding,0) & ']'
    • 使用numtostr将开平仓条件、持仓转换成字符串后。与其他字符串拼接。以增加整个日志文件的可读性。
  • 参数3:0 。
    • 任意数字,在此处没有实质性作用,仅是占位使用。

debugfile日志输出如下:

日志文件名:T_P00.txt

       1                    2         3                       4
----------------------------------------------------------------------------------
2022-04-08 10:06:00.284    P00   [开仓条件=0]   各项条件:[开多条件1=0   持仓手数=0]
2022-04-08 10:06:00.286    P00   [平仓条件=0]   各项条件:[平仓条件1=0   持仓手数=0]
2022-04-08 10:06:01.092    P00   [开仓条件=0]   各项条件:[开多条件1=0   持仓手数=0]
2022-04-08 10:06:01.092    P00   [平仓条件=0]   各项条件:[平仓条件1=0   持仓手数=0]
2022-04-08 10:06:01.096    P00   [开仓条件=0]   各项条件:[开多条件1=0   持仓手数=0]
2022-04-08 10:06:01.097    P00   [平仓条件=0]   各项条件:[平仓条件1=0   持仓手数=0]
2022-04-08 10:06:01.909    P00   [开仓条件=0]   各项条件:[开多条件1=0   持仓手数=0]
2022-04-08 10:06:01.910    P00   [平仓条件=0]   各项条件:[平仓条件1=0   持仓手数=0]
2022-04-08 10:06:02.721    P00   [开仓条件=0]   各项条件:[开多条件1=0   持仓手数=0]
2022-04-08 10:06:02.722    P00   [平仓条件=0]   各项条件:[平仓条件1=0   持仓手数=0]
2022-04-08 10:06:03.531    P00   [开仓条件=0]   各项条件:[开多条件1=0   持仓手数=0]
2022-04-08 10:06:03.532    P00   [平仓条件=0]   各项条件:[平仓条件1=0   持仓手数=0]
2022-04-08 10:06:04.344    P00   [开仓条件=0]   各项条件:[开多条件1=0   持仓手数=0]
2022-04-08 10:06:04.344    P00   [平仓条件=0]   各项条件:[平仓条件1=0   持仓手数=0]
2022-04-08 10:06:05.161    P00   [开仓条件=0]   各项条件:[开多条件1=0   持仓手数=0]
2022-04-08 10:06:05.161    P00   [平仓条件=0]   各项条件:[平仓条件1=0   持仓手数=0]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18