如果交易策略中使用了参数,而且参数值关系到策略的进出场点或者交易头寸,那么策略的测试效果将和参数值的设置密不可分,因此选择最优的参数是策略测试和优化的重要工作之一。在参数优化的实际过程中,用户除了需要得到优化报告选择应用最佳参数之外,还有更多需求,例如:查看策略参数优化的历史报告,可将最佳参数应用到其他使用同一策略的不同图表中;合理分配优化任务及时间,使其不影响计算机日常使用时的性能,或者将影响降至最低。新版本中提供的参数“批量优化”功能,就是针对这类问题设计的。

数组可以用来定义变量,也可以用作函数的参数,通过数组变量和参数,可以批量操作多个数据。

新版本TB支持三种类型的数组:布尔型、数值型和字符串类型,数组有一维或多维,TB目前只支持一维数组。


1、数组声明

在使用数组之前,必须对数组进行声明,用法和普通的变量和参数一样。
数组参数声明时不支持指定大小,数组变量声明时可以指定数组的大小,语法格式如下:
Params
数组类型 变量名1;
数组类型 变量名2;
Vars
数组类型 变量名1[数组大小];
数组类型 变量名2[数组大小];
例:
Params
NumericArray  arr;    //定义数值型数组arr
BoolArrayRef  bArr;     //定义布尔型引用数组bArr
StringArray  name;    //定义字符串类型数组name
Vars
NumericArray  MyArr1[8];    //定义数值型数组MyArr1,指定数组大小为8
BoolArray   MyArr2[100];     //定义布尔型数组MyArr2,指定数组大小为100
StringArray   MyArr3;      //定义字符串数组MyArr3,不指定数组大小


为了提升程序运行的效率,建议在使用数组参数时,尽量使用引用参数。如果不希望修改传入数组的值,可以在内部新建数组变量进行赋值,示例如下:
Parmas
NumericArrayRef arr;
Vars
NumericArray tempArr;
Begin
tempArr = arr;
// 以下对tempArr进行计算和修改
...
End


2、数组使用

数组声明之后,可在脚本正文中对其进行赋值、计算等操作。数组通常配合循环语句使用,可控制循环计数或存储循环中的数据,简化代码。数组元素通过“数组名[下标]”进行访问。

【案例一】创建一个数组,长度为10,依次存放0-9这10个数字。代码如下:
Vars
NumericArray arr[10];
Numeric i;
Begin
For i = 0 To 9
{
arr[i] = i;
}
End

【案例二】数组求和。
Params
NumericArrayRef arr;
Vars
Numeric arrSize;     //定义变量,存放数组的大小
Numeric sumValue(0);     //定义变量,存放求和结果
Numeric i;     //循环变量
Begin
arrSize = GetNumericArraySize(arr); //通过函数求出数组的大小
For i = 0 To arrSize
{
sumValue = sumValue + arr[i]; //累加求和
}
return sumValue;
End

【案例三】求数组中的最大值。
Params
NumericArrayRef arr;
Vars
Numeric arrSize;      //定义变量,存放数组的大小
Numeric maxValue;     //定义变量,存放最大值
Numeric i; //循环变量
Begin
arrSize = GetNumericArraySize(arr);     //通过函数,求出数组的大小
maxValue = arr[0];      //将最大值赋值为数组中第一个元素
For i = 1 To arrSize    //最大值与数组中的元素依次比较,若数组元素值大,将其赋给最大值
{
If (arr[i] > maxValue)
{
maxValue = arr[i];
}
}
return maxValue;
End

注:为了方便使用,用户在使用TB的数组时可以不指定数组大小,系统会在使用时动态分配,在没有通过数组函数SetNumericArraySize指定初始值时,会使用无效值来动态生成数组并指定值。


3、数组函数

TB提供了一组数组函数支持数组的使用,方便用户实现动态调节数组大小、获取数组大小、对数组的值进行排序等等操作,函数详细说明如下:

BoolArrayClear: 布尔型数组的全部删除。
语法 void BoolArrayClear(BoolArrayRef arr)
参数 arr 要全部删除的数组。
备注 布尔型数组的全部删除,无返回值。

BoolArrayCompare: 对两个布尔型数组进行比较。
语法 Integer BoolArrayCompare(BoolArrayRef lh, Integer pos, BoolArrayRef rh, Integer startIndex, Integer count)
参数 lh 参与比较的数组1;pos 数组1的比较起始位置;rh 参与比较的数组2;startIndex 数据2的比较起始位置;count 比较的数组元素个数。
备注 对两个布尔型数组进行比较,返回值为整型。为0表示比较的内容相等,1表示lh大于rh,-1表示lh小于rh。

BoolArrayCopy: 复制布尔型数组的内容。
语法 void BoolArrayCopy(BoolArrayRef src, BoolArrayRef dst)
参数 src 复制的源数组;dst 复制的目的数组;
备注 复制布尔型数组的内容,无返回值。

BoolArrayEqual: 检验两个布尔型数组是否相等。
语法 Bool BoolArrayEqual(BoolArrayRef lh, BoolArrayRef rh)
参数 lh 进行比较的数组1;rh 进行比较的数组2。
备注 检验两个布尔型数组是否相等,返回值为布尔型。

BoolArrayErase: 布尔型数组的元素删除。
语法 void BoolArrayErase(BoolArrayRef arr, Integer pos, Integer count)
参数 arr 要删除的数组;pos 删除的起始位置;count 删除的数组元素个数。
备注 布尔型数组的元素删除,无返回值。

BoolArrayInsert: 布尔型数组的单个数据插入。
语法 void BoolArrayInsert(BoolArrayRef arr, Integer pos, Numeric val)
参数 arr 要插入的数组;pos 插入数据的起始位置;val 插入的数据值。
备注 布尔型数组的单个数据插入,无返回值。

BoolArrayInsertRange: 布尔型数组的多个数据插入。
语法 Integer BoolArrayInsertRange(BoolArrayRef arr, Integer pos, BoolArrayRef src, Integer startIndex, Integer count)
参数 arr 要插入的数组;pos 插入数据的起始位置;src 插入数据的源数组;startIndex 源数组的插入起始位置;count 插入数组元素个个数。
备注 布尔型数组的多个数据插入,无返回值。

BoolArraySort: 对布尔型数组进行排序。
语法 void BoolArraySort(BoolArrayRef arr, Bool ascending)
参数 arr 要进行排序的数组;ascending 升序还是降序排列,为True表示升序。
备注 对布尔型数组进行排序,无返回值。

BoolArraySwap: 交换布尔型数组的内容。
语法 void BoolArraySwap(BoolArrayRef lh, BoolArrayRef rh)
参数 lh 进行交换的数组1;rh 进行交换的数组2。
备注 交换布尔型数组的内容,无返回值。当需要对比较大的数组进行赋值时,会比较耗费资源,如果确定源数组不再使用时,可通过交换函数提升效率。

GetBoolArraySize: 获取布尔型数组的大小。
语法 Integer GetBoolArraySize(BoolArrayRef arr)
参数 arr 需要获取大小的数组。
备注 获取布尔型数组的大小,返回值为整型。

GetNumericArraySize: 获取数值型数组的大小。
语法 Integer GetNumericArraySize(NumericArrayRef arr)
参数 arr 需要获取大小的数组。
备注 获取数值型数组的大小,返回值为整型。

GetStringArraySize: 获取字符串数组的大小。
语法 Integer GetStringArraySize(StringArrayRef arr)
参数 arr 需要获取大小的数组。
备注 获取字符串数组的大小,返回值为整型。

NumericArrayClear: 数值型数组的全部删除。
语法 void NumericArrayClear(NumericArrayRef arr)
参数 arr 要全部删除的数组。
备注 数值型数组的全部删除,无返回值。

NumericArrayCompare: 对两个数值型数组进行比较。
语法 Integer NumericArrayCompare(NumericArrayRef lh, Integer pos, NumericArrayRef rh, Integer startIndex, Integer count)
参数 lh 参与比较的数组1;pos 数组1的比较起始位置;rh 参与比较的数组2;startIndex 数据2的比较起始位置;count 比较的数组元素个数。
备注 对两个数值型数组进行比较,返回值为整型。为0表示比较的内容相等,1表示lh大于rh,-1表示lh小于rh。

NumericArrayCopy: 复制数值型数组的内容。
语法 void NumericArrayCopy(NumericArrayRef src, NumericArrayRef dst)
参数 src 复制的源数组;dst 复制的目的数组;
备注 复制数值型数组的内容,无返回值。

NumericArrayEqual: 检验两个数值型数组是否相等。
语法 Bool NumericArrayEqual(NumericArrayRef lh, NumericArrayRef rh)
参数 lh 进行比较的数组1;rh 进行比较的数组2。
备注 检验两个数值型数组是否相等,返回值为布尔型。

NumericArrayErase: 数值型数组的元素删除。
语法 void NumericArrayErase(NumericArrayRef arr, Integer pos, Integer count)
参数 arr 要删除的数组;pos 删除的起始位置;count 删除的数组元素个数。
备注 数值型数组的元素删除,无返回值。

NumericArrayInsert: 数值型数组的单个数据插入。
语法 void NumericArrayInsert(NumericArrayRef arr, Integer pos, Numeric val)
参数 arr 要插入的数组;pos 插入数据的起始位置;val 插入的数据值。
备注 数值型数组的单个数据插入,无返回值。

NumericArrayInsertRange: 数值型数组的多个数据插入。
语法 Integer NumericArrayInsertRange(NumericArrayRef arr, Integer pos, NumericArrayRef src, Integer startIndex, Integer count)
参数 arr 要插入的数组;pos 插入数据的起始位置;src 插入数据的源数组;startIndex 源数组的插入起始位置;count 插入数组元素个个数。
备注 数值型数组的多个数据插入,无返回值。

NumericArraySort: 对数值型数组进行排序。
语法 void NumericArraySort(NumericArrayRef arr, Numeric ascending)
参数 arr 要进行排序的数组;ascending 升序还是降序排列,为True表示升序。
备注 对数值型数组进行排序,无返回值。

NumericArraySwap: 交换数值型数组的内容。
语法 void NumericArraySwap(NumericArrayRef lh, NumericArrayRef rh)
参数 lh 进行交换的数组1;rh 进行交换的数组2。
备注 交换数值型数组的内容,无返回值。当需要对比较大的数组进行赋值时,会比较耗费资源,如果确定源数组不再使用时,可通过交换函数提升效率。

SetBoolArraySize: 设置布尔型数组的大小和初始值。
语法 void SetBoolArraySize(BoolArrayRef arr, Integer count, Bool defaultValue)
参数 arr 需要设置大小和初始值的数组;count 数组初始化的大小;defaultValue 布尔型数组的初始值。
备注 设置布尔型数组的大小和初始值,无返回值。

SetNumericArraySize: 设置数值型数组的大小和初始值。
语法 void SetNumericArraySize(NumericArrayRef arr, Integer count, Numeric defaultValue)
参数 arr 需要设置大小和初始值的数组;count 数组初始化的大小;defaultValue 数值型数组的初始值。
备注 设置数值型数组的大小和初始值,无返回值。

SetStringArraySize: 设置字符串数组的大小和初始值。
语法 void SetStringArraySize(StringArrayRef arr, Integer count, String defaultValue)
参数 arr 需要设置大小和初始值的数组;count 数组初始化的大小;defaultValue 字符串数组的初始值。
备注 设置字符串数组的大小和初始值,无返回值。

StringArrayClear: 字符串数组的全部删除。
语法 void StringArrayClear(StringArrayRef arr)
参数 arr 要全部删除的数组。
备注 字符串数组的全部删除,无返回值。

StringArrayCompare: 对两个字符串数组进行比较。
语法 Integer StringArrayCompare(StringArrayRef lh, Integer pos, StringArrayRef rh, Integer startIndex, Integer count)
参数 lh 参与比较的数组1;pos 数组1的比较起始位置;rh 参与比较的数组2;startIndex 数据2的比较起始位置;count 比较的数组元素个数。
备注 对两个字符串数组进行比较,返回值为整型。为0表示比较的内容相等,1表示lh大于rh,-1表示lh小于rh。

StringArrayCopy: 复制字符串数组的内容。
语法 void StringArrayCopy(StringArrayRef src, StringArrayRef dst)
参数 src 复制的源数组;dst 复制的目的数组;
备注 复制字符串数组的内容,无返回值。

StringArrayEqual: 检验两个字符串数组是否相等。
语法 Bool StringArrayEqual(StringArrayRef lh, StringArrayRef rh)
参数 lh 进行比较的数组1;rh 进行比较的数组2。
备注 检验两个字符串数组是否相等,返回值为布尔型。

StringArrayErase: 字符串数组的元素删除。
语法 void StringArrayErase(StringArrayRef arr, Integer pos, Integer count)
参数 arr 要删除的数组;pos 删除的起始位置;count 删除的数组元素个数。
备注 字符串数组的元素删除,无返回值。

StringArrayInsert: 字符串数组的单个数据插入。
语法 void StringArrayInsert(StringArrayRef arr, Integer pos, String val)
参数 arr 要插入的数组;pos 插入数据的起始位置;val 插入的数据值。
备注 字符串数组的单个数据插入,无返回值。

StringArrayInsertRange: 字符串数组的多个数据插入。
语法 Integer StringArrayInsertRange(StringArrayRef arr, Integer pos, StringArrayRef src, Integer startIndex, Integer count)
参数 arr 要插入的数组;pos 插入数据的起始位置;src 插入数据的源数组;startIndex 源数组的插入起始位置;count 插入数组元素个个数。
备注 字符串数组的多个数据插入,无返回值。

StringArraySort: 对字符串数组进行排序。
语法 void StringArraySort(StringArrayRef arr, Bool ascending)
参数 arr 要进行排序的数组;ascending 升序还是降序排列,为True表示升序。
备注 对字符串数组进行排序,无返回值。

StringArraySwap: 交换字符串数组的内容。
语法 void StringArraySwap(StringArrayRef lh, StringArrayRef rh)
参数 lh 进行交换的数组1;rh 进行交换的数组2。
备注 交换字符串数组的内容,无返回值。当需要对比较大的数组进行赋值时,会比较耗费资源,如果确定源数组不再使用时,可通过交换函数提升效率。

4、数组在实际交易策略编程中的应用

随着量化交易在国内的迅速普及和快速发展,量化策略的研究也不断深入。量化策略的优势除了体现在买卖时机的量化方面,更应该体现在交易标的量化选择方面,如:量化选股、量化对冲等。这种以大量数据运算为基础的策略,在编程时离不开数组功能的支持。

【案例四】交易标的的强弱排序策略

具体规则:选择三大商品交易所交易比较活跃的主力商品合约作为候选交易标的,以20根BAR的涨跌幅作为强弱比较的标准,再根据强弱排名制定交易策略。 代码如下(交易部分省略…):
Params
Numeric Length(20);    // 多少根BAR的涨跌幅
Vars
NumericArray ChangeRate;    // 保存涨跌幅的数组
NumericArray Rank;     // 保存数据源的数组
Numeric i;
Numeric j;
Numeric temp;
Begin
// 计算图表所有品种Length根BAR以来的涨跌幅
For i = 0 to DataCount - 1
{
// 涨跌幅数据保存到一个数组
ChangeRate[i] = Round((Data[i].Close / Data[i].Close[Length] - 1)*100,2);
// 数据源编号保存到另一个数组
Rank[i] = i;
}

// 冒泡排序(降序)
For i = 1 to DataCount - 1
{
For j = 0 to DataCount - 1 - i
{
If(ChangeRate[j] < ChangeRate[j+1])
{
// 涨跌幅数据交换顺序
temp = ChangeRate[j];
ChangeRate[j] = ChangeRate[j+1];
ChangeRate[j+1] = temp;

// 对应的数据源编号交换顺序
temp = Rank[j];
Rank[j] = Rank[j+1];
Rank[j+1] = temp;
}
}
}

// 显示排序后的排名
For i = 0 to DataCount - 1
{
temp = Rank[i];
Commentary("【Rank"+Text(i+1)+"】: Data"+Text(temp)+" , "+Data[temp].Symbol+" , ChangeRate = "+Text(ChangeRate[i])+" %");
}
End

在图表中插入23个主力交易品种后运行结果如下:

【关联知识点】上面的代码中,在对图表中所有品种进行循环处理时使用Data[i].Close这样一种用法,即可以对数据源的编号使用变量,这个也是新版才支持的功能。