# 变量对比

本节只围绕普通变量、VARIABLE、GLOBALVARIABLE三者在K线上执行的关系进行分析。希望可以帮助大家进一步理解全局变量的特性。

普通变量:策略每次被执行,普通变量都会进行一次初始化操作,即普通变量每次执行策略都被创建和销毁。前后两次的运行结果并不会被传递。

VARIABLE变量:当策略在第一根K上被执行时,VARIABLE变量进行初始化操作,之后VARIABLE变量都基于上根K上的最终结果进行运算;

  • 补充:在最新k上时,策略虽然会被多次执行,但是VARIABLE变量同样是使用上根k上的最终结果在最新k上运算,即VARIABLE变量无法获得同根k上的上次执行结果。
  • 此变量应用于图表。

GLOBALVARIABLE变量:当策略被加载启用时,GLOBALVARIABLE变量进行初始化操作,GLOBALVARIABLE变量的仅在最新k上有效并且基于上一次的运行结果进行运算。

  • 此变量应用于后台。

EXT***变量:它等于一个微型数据库,适用也非常简单,通过写入函数EXTGBDATASET和读取函数EXTGBDATA直接操作即可。类似于生活使用便签纸留言,将备忘内容写上后,再在指定的地方读取即可。

说明

  1. 它不存在初始化过程,不会因为软件重启等因素的影响而发生变化。
  2. 它作用于整个金字塔中,因此在使用EXTGBDATASET写入数据时,要留心变量名因为重复造成的干扰。
    例如:A策略和B策略之间本身不存在交互行为,但是通过EXTGBDATASET写入同为X变量的值。那么A策略和B策略之间则产生了干扰。这种干扰会造成两个策略的执行逻辑发生紊乱。

SETREGVAL和SETREGVAL:它们代表的两组函数,分别是操作配置文件和注册表。其作用范围都是整个计算机,通过它们可以做到客户端之间的交互。两组函数唯一的区别在于记录的数据位置不同。

变量标识 名称类型 作用范围 解析
普通变量 单根K线 只在当根K线生效,当指标换到下一根K线进行计算时就会被再次初始化。
VARIABLE 全局变量 首根K至最后一根k线 指标加载后,定义语句在第一根K线处初始化为设定值,后面的K线调用此全局变量计算时,调用到的值是上一根K线计算的返回值。当行情更新,指标重新刷新时,那么此变量又会在第一根K线处被定义语句初始化。
GLOBALVARIABLE 超全局变量 指标加载至停止运行期间 指标加载时对全局变量定义的语句进行一次初始化,之后定义语句都不会再对其初行初始化直至停止运行指标。
EXTGBDATA 单值全局变量 整个金字塔软件范围内 设置了初始值之后,只要是在金字塔软件范围内,任意的指标、手工或者其他方式都可软修改它的值,并且在整个软件范围内共享这个值。因此,它不存在绝对意义的初始化。
SETREGVAL 注册表全局变量 整个计算机范围内 将变量存储机注册表中,因此在整都计算机内都可以调用这个值。
WRITEINIFILE 写配置文件 整个计算机范围内 将变量存储在本地配置文件内,因此在整都计算机内都可以该配置文件调用这个值。

# 全局变量的应用

应用遵循规则

  1. 全局变量的整个变化过程应该形成一个闭环,即初始值-->赋值1-->赋值2-->...-->初始值.
  2. 全局变量用于状态标记时,每种状态应该对应一个状态值,否者逻辑可能发生紊乱。

全局变量的使用场景一般就是以下几种情况:

1. 作为统计数量控制使用,例如:在双均线指标中,控制每天开仓次数不大于5次。
// 定义全局变量,来控制当天交易次数
variable:num=0;

//限定一天最多交易5次
cs:=5;

ma5:ma(close,5);
ma20:ma(close,20);
cond1:=cross(ma5,ma20);
cond2:=cross(ma20,ma5);

//开仓条件,其中子条件num<cs用于判断控制开仓次数。
if cond1 and holding=0 and num<cs  then 
begin
	buy(1,1,market);
	num:=num+1;
end

if cond2 and holding>0 then sell(1,1,market);

// 收盘时将num赋值为0,否者第二天无法再进行开仓
if time=closetime(0) then num:=0;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

说明

  1. 图表策略只能使用variable全局变量,其他全局变量不符合图表的运行计算机制慎用。
  2. 后台策略推荐使用GLOBALVARIABLE,如果使用ext全局变量控制时,需要注意ext定义的变量名,否者在多品种多测策略操作时,存在相同的ext变量名时,结果会紊乱。
2. 控制策略逻辑执行的先后关系(逻辑互锁、层级关系);例如:当日开仓后,要求次日平仓。
//该策略适用于图表程序化交易
//该策略适用于分钟周期
//仅供演示使用,请勿直接用于实盘

VARIABLE:FLAG=0;     //定义全局变量标记FLAG,初始值为0
INPUT:SS(1,1,100,1); //定义开仓手数

//交易条件
N:BARSLAST(DATE<>REF(DATE,1))+1;  //当日K线数量
MA5:=MA(C,5);
MA20:=MA(C,20);
CON1:CROSS(MA5,MA20) AND N>=3;
CON2:CROSS(MA20,MA5) AND N>=3;

//开仓语句。开仓后,FLAG标记置为1
IF CON1 THEN BEGIN
    BUY(HOLDING=0,SS,MARKET);
    FLAG:=1;
END 

//平仓语句  
IF CON2 AND FLAG=0 THEN begin
    SELL(HOLDING>0,HOLDING,MARKET);
end
    
//交易日结束时,FLAG平仓标记置为0;
IF TIME=CLOSETIME(0) THEN begin
    FLAG:=0;
end                                          
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

说明

  1. 使用全局变量互锁特性,将每个逻辑通过唯一的ID编码进行排列,从而形成特有的执行过程。

通过上述代码的学习,我们大致了解逻辑互锁的整个过程,那么实际使用中,这种方法更常用于分阶段性加减仓逻辑管理中。如下代码:

//持仓2手,如果赢利在75-100个价位之间开始回落,
//盈利回落到15个价位以内时止盈平仓1手,之后回落亏损20个价位后触发止损结束。

VARIABLE:sellflag=0;

//盈利在75-100个价位之间时,标记状态,用此状态开启回落止盈止损逻辑监测
IF C-AvGENTERPRICE>=75*MINDIFF and C-AvGENTERPRICE<100*MINDIFF and sellflag=0 THEN BEGIN
    sellflag:=1;
END

// 盈利已经离开75-100区间,回落至盈利15个价位以内时。
IF C-AvGENTERPRICE<=15*MINDIFF and sellflag=1 THEN BEGIN
    SELL(1,1,MARKET);
END

IF AvGENTERPRICE-C>=20*MINDIFF and sellflag=1 THEN BEGIN
    SELL(1,1,MARKET);
    //仓位已经平完,状态重置为初始值,等待进行下次开仓
    sellflag:=0;
END
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
3. 使用EXT***类实现多策略之间数据共享。例如:计算A、B两策略中A_X和之和。

A策略

//赋值A_X=3
EXTGBDATASET('A_X',3);
1
2

B策略

//赋值B_Y
EXTGBDATASET('B_Y',7);
1
2

计算A、B两策略之和。

SUM_AB:=EXTGBDATA('A')+EXTGBDATA('B')
1

上述简单逻辑可以帮助我们理解EXT***全局变量进行数据传递的特点,EXT***全局变量也是实现净持仓统计的方法之一。

说明

  1. EXT***类的全局变量没有历史值,它只适用于后台策略中,
  2. 它也可以像其他全局变量一样,应用在计数统计逻辑互锁的使用场景中。
4. 使用EXT***全局变量实现移动止损功能
//A有三种数值状态:1,0,最新价;
//当A=1时表示当前有持仓,A=0时表示移动止损执行完毕,A=最新价时用于比较价格是否回落

//将A赋值为1,表示当前有持仓
IF TBUYHOLDINGEX( '','' ,0 )>0 AND EXTGBDATA('a' )=0 THEN BEGIN
EXTGBDATASET( 'a',1 );
END

//使A始终表示监控开始后的最高价
IF DYNAINFO(  7)>EXTGBDATA('a' ) and EXTGBDATA('a' )>0 THEN BEGIN
EXTGBDATASET( 'a',DYNAINFO(  7));
END

//发现价格回落止损,并将A赋值为0表示移动止损动作完成
IF EXTGBDATA('a' )-DYNAINFO(  7)>5*MINDIFF and EXTGBDATA('a' )>0 THEN BEGIN
TSELL(1,1,MKT );
EXTGBDATASET( 'a',0);
END
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
上述移动止损为什么不使用GLOBALVARIABLE全局变量实现?

因为移动止损中的最高价是判断回落的依据,在实际使用中,我们不希望它受到重启等因素的影响而发生变化。因此采用EXT***是最佳解决方法。

由于EXT***全局变量时公共的,如何才能让上述代码适合多品种,避免之间产生干扰?

我们只需要在设置EXT***全局变量时,保证变量名称的唯一性即可。因此使用STKLABEL函数与变量a组合成变量名即可。
注意:如果是多策略同品种交易,可以使用FORMULANAME作为区分名称的一部分。(策略名称尽可能简单,否者容易超出长度限制)

//A有三种数值状态:1,0,最新价;
//当A=1时表示当前有持仓,A=0时表示移动止损执行完毕,A=最新价时用于比较价格是否回落

//将A赋值为1,表示当前有持仓
IF TBUYHOLDINGEX( '','' ,0 )>0 AND EXTGBDATA(STKLABEL&'_a' )=0 THEN BEGIN
EXTGBDATASET( STKLABEL&'_a',1 );
END

//使A始终表示监控开始后的最高价
IF DYNAINFO(  7)>EXTGBDATA(STKLABEL&'_a' ) and EXTGBDATA(STKLABEL&'_a' )>0 THEN BEGIN
EXTGBDATASET( STKLABEL&'_a',DYNAINFO(  7));
END

//发现价格回落止损,并将A赋值为0表示移动止损动作完成
IF EXTGBDATA(STKLABEL&'_a' )-DYNAINFO(  7)>5*MINDIFF and EXTGBDATA(STKLABEL&'_a' )>0 THEN BEGIN
TSELL(1,1,MKT );
EXTGBDATASET( STKLABEL&'_a',0);
END
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18