上一讲:期货CTP接口与程序化(量化交易)的对接(2)
序列变量的载体上一讲举了一个简单的例子,现在继续用这个例子来讲解。
它使用的策略是:长阳达到X且在均线之上买进,长阴达到X且在均线之下买进。代码是:
public class Signal //信号结构体
{
//定义信号数据,自己写
public Signal(string 下单方式)
{
//根据买开还是买平还是卖开还是卖平什么的,信号数据怎么变,自己写
}
}
public class Strg //策略管理器
{
static List K线序列 = new List();
static List 均线序列 = new List();
//K线序列,有行情模块给它增加元素,这里不用管
//但均线序列需要在这里增加
static void 更新均线(int N) //这个函数是简化了的,它是假设每根K线只更新一次均线的算法
{ //若要每个tick都更新均线,代码就比较多了,这里先不说
if (N <= 0) return;
int K线根数 = K线序列.Count;
if (K线根数 < N) return;
if (K线根数 == N)
{
double sum = 0;
for (int i = 0; i N)
{
double 上一根K线的均线值 = 均线序列.Last();
double 当前K线的均线值 = 上一根K线的均线值 + (K线序列.Last() - K线序列[K线根数 - 1 - N]) / (double)N;
均线序列.Add(当前K线的均线值);
}
}
public static List 傻瓜策略(double X, int N, double 最高价, double 最低价, double 开盘价)
{
List signals = new List();
更新均线(N);
if (均线序列.Count <= 0) return signals;
double 均线 = 均线序列.Last();
if (均线 = 开盘价 + X && 最高价 >= 均线)
{
signals.Add(new Signal("买平"));
signals.Add(new Signal("买开"));
}
else if (最低价 <= 开盘价 - X && 最低价 <= 均线)
{
signals.Add(new Signal("卖平"));
signals.Add(new Signal("卖开"));
}
return signals;
}
}
这里面用到了一个叫做“均线序列”的序列变量。上一讲讲过,使用序列变量是为了提高计算效率,序列变量的算法,是用上一根K线的数据推导当前K线的数据,而不需要把N根K线拿来统统算一遍。在程序化实际工作中,这是不得不采用的,否则你的实盘根本跑不动。计算速度加快了,代码却更多了,让程序员更烧脑了。
现在又一个新问题会让程序员更头疼。序列变量的转移。
如果所有的变量都留在上面的框里,都老老实实地待在这儿,那就简单了。但是,你的序列变量很有可能要跑到别的模块里去搞事情,比如均线这个变量,它至少要到画图模块里去指挥画线。
在实际工作中,序列变量还有很多:
所有的指标
所有的标记、线条、方框等
行情方向(可能需要分成大趋势、中趋势、小趋势)
行情峰谷的位置和价格
持仓信息
各种开仓的位置和成本
条件单
……
这些都要跑到不同的模块里去显示,或者指导交易,或者起别的作用,而且,它们是一起跑的,每当执行一次策略函数,这些变量都变了,就都要输出,它们是组团转移的。
更麻烦的是,当不同的合约使用同一策略时,每个合约都有这样的一套变量,这个合约的均线与那个合约的均线是不一样的,这样一来,你就更不能把均线记录在一个地方了。像上述代码那样,在与策略函数同级的位置定义均线序列,不好使了,试想,一个合约的均线记录在这儿,另一个合约的均线也记录在这儿,甚至同一个合约的不同周期的均线也记录在这儿,哪里还分得清。
所以需要这个东西:序列变量的载体。它主要有两个作用:
1.当序列变量需要组团转移时,这个载体给它们打包,简化操作。
2.每个交易方案(合约、周期、策略参数的每个组合),都有自己独特的载体,这样,甲方案的均线就不会与乙方案的均线混淆。
这个载体,是C#的一个结构体,举例如下:
public class StrgData //序列变量载体,每个交易方案都要有这样的一个东西来记录其特有的序列变量
{
public List 均线序列 = new List();
public List signals = new List();
//还有很多其他序列变量
//这里不写出来了
}
策略的代码变成了:
public class StrgData //序列变量载体,每个交易方案都要有这样的一个东西来记录其特有的序列变量
{
public List 均线序列 = new List();
public List signals = new List();
//还有很多其他序列变量
//这里不写出来了
}
public class Signal //信号结构体
{
//定义信号数据,自己写
public Signal(string 下单方式)
{
//根据买开还是买平还是卖开还是卖平什么的,信号数据怎么变,自己写
}
}
public class Strg //策略管理器
{
public static List K线序列 = new List();
public static Dictionary strgDatas = new Dictionary(); //各交易方案的序列变量载体,键为交易方案名称,值为序列变量载体
//假如说有一个交易方案叫做“把傻瓜策略用在聚丙烯上”,那么它的序列变量载体就是strgDatas["把傻瓜策略用在聚丙烯上"]
static void 更新均线(int N, ref StrgData strgData) //这个函数是简化了的,它是假设每根K线只更新一次均线的算法
{ //若要每个tick都更新均线,代码就比较多了,这里先不说
if (N <= 0) return;
int K线根数 = K线序列.Count;
if (K线根数 < N) return;
if (K线根数 == N)
{
double sum = 0;
for (int i = 0; i N)
{
double 上一根K线的均线值 = strgData.均线序列.Last();
double 当前K线的均线值 = 上一根K线的均线值 + (K线序列.Last() - K线序列[K线根数 - 1 - N]) / (double)N;
strgData.均线序列.Add(当前K线的均线值);
}
}
public static void 傻瓜策略(double X, int N, ref StrgData strgData, double 最高价, double 最低价, double 开盘价)
{
更新均线(N, ref strgData);
if (strgData.均线序列.Count <= 0) return;
double 均线 = strgData.均线序列.Last();
if (均线 = 开盘价 + X && 最高价 >= 均线)
{
strgData.signals.Add(new Signal("买平"));
strgData.signals.Add(new Signal("买开"));
}
else if (最低价 <= 开盘价 - X && 最低价 <= 均线)
{
strgData.signals.Add(new Signal("卖平"));
strgData.signals.Add(new Signal("卖开"));
}
}
}