欢迎您光临博庭社区!

 找回密码
 立即注册
查看: 31978|回复: 101

自制《金语言初级教程》--从0开始学习金语言   [复制链接]

Rank: 3Rank: 3

发表于 2013-8-14 13:50:11 |显示全部楼层
本帖最后由 hslixuexue 于 2017-10-30 17:06 编辑

    根据官方素材加以整理,同时加上少量个人理解,制作的一个教程。适合于从0开始的新手。对高手没有多大意义。本教程非常初级旨在建立对金语言框架体系的一个概念性的认识,能读懂金语言、有了想法之后能够去摸索,而不是经验技巧。不过希望高手能修正,让大家得以提高。或者当做个人读书笔记。
    教程尚未完善,需要不停修正与更新。如果纠正错误、理解更新,会在原帖更新。教程内容紧跟自己学习过程。说不定可以追上金魔方开发进度。
    在网上搜索时,发现各种类似软件关键命令,好像概念差不多,比如easylanguage、金字塔、开拓者等,就算是具体格式不同,懂了原理,根据字典就行修正不就行了嘛!因此不知道是不是可以当做新手进行量化交易编程的通用教程。欢迎交流qq:20639986对于一些能解决的程序问题,只要大家愿意交流,我一定会帮助。但是水平有限,更主要的是时间太少,所以解决时间较长。我每5天值班一次,当天时间最多。
    目录    第一部分 基础部分
    一、程序语言基本概念
    二、数据类型
    三、操作符
    四、变量
    五、中间变量
    六、参数、参数精灵
    七、语句
    八、函数
    九、程序
    十、公式/程序的使用
    十一、公式执行模式:逐根和逐行(20130817更新)
    十二、公式类型/量化交易策略
    十三、自动交易系统模型十三自动交易系统模型
    十四、自动交易指令详解
    十五、实盘函数
    十六、指标输出
    十七、线形描述
    十八、绘图函数
    第二部分 内置函数介绍部分
       (这部分只是把公式手册变成word格式,少量理解,对量大的类别进行简单分类。犹豫一阵,相当于编辑了一下,没得必要发了吧)。放上Word版,让大家可以做学习笔记。
   
       第三部分 上手
   
五十二、高度浓缩的软件使用帮助
       五十三、评测报告指标详解
       五十四、dll调用      
    五十五、简单策略逐行解读一
    五十六、简单策略逐行解读二:分批开平仓
   
    五十七、简单策略逐行解读三:指标背离交易及风险控制策略
   
五十八、简单策略逐行解读四:自动趋势线交易策略
    五十九、简单策略逐行解读五:网格交易和鞅加仓策略
    六十、简单策略逐行解读六:点数图突破交易策略
    六十一、简单策略逐行解读七:均线与趋势线交叉加仓位管理
    六十二、简单策略逐行解读八:向前引用 示范模型  
    六十三、简单策略逐行解读九:瀑布线 示范模型  
    六十四、简单策略逐行解读十:DMA-QL钱龙趋向 示例模型  
    六十五、简单策略逐
行解读十一:当根K线开仓模型  
    六十六、简单策略逐行解读十二:日线四价引用示例模型  
    六十七、简单策略逐行解读十三:异同离差乖离率 示例模型  
    六十八、简单策略逐行解读十四:价差型模型示例  
    六十九、简单策略逐行解读十五:慢速KD 示例模型  
    七十、简单策略逐行解读十六:MIKE 示范模型  
    七十一、简单策略逐行解读十七:时间函数 示例模型  
    七十二、简单策略逐行解读十八:多条件模型示例  
    七十三、编程简易模板
    七十四、根据开启投机波动密码群天骄大哥:一张图片编制简易函数
(第二个代码忘了修改,现在修改了)       
   
  七十五、 关于参数、变量、中间变量的补充                                                                                            七十六 、编程模板的补充鹿希武趋势交易法趋势线和拐点线、数据规则、语句规则)
    七十七 、德马克指标
   

    不知道该不该在这个版块发帖,没有新手版块,那个软件使用学习版块我发不起贴,始终提示我做新手任务,新手任务又是空的,而且无法邮箱验证。呵呵。
    另外,是word制作的,帖子的时候,格式很乱,用word重新调一下格式,可能看起来顺一点。word格式的好处就是,自己可以随意修改,当做学习笔记。

附件: 你需要登录才可以下载或查看附件。没有帐号?立即注册

使用道具 举报

Rank: 3Rank: 3

发表于 2013-8-14 13:57:21 |显示全部楼层
    一、程序语言基本概念
    字符:大小写英文字母(56)个。十进制数字。标点符号。运算符。金语言代码不区分字母的大小写,字母可以大写,也可以小写或者大小写混合。DLL调用的函数声明除外,此时是区分大小写的。
    单词:语言字符构成语言单词。5种。
    1、保留字:语言系统预定义,小写字母组成的,单词或者词头、词组。预处理命令中的命令关键字,不是保留字,最好当做保留字。如C代表收盘价,H代表最高价。
    2、标识符。标识符是给特定量(变量、符号常量、对象、自定义数据类型、函数)起的名字。由英文字母、十进制字符、下划线组成,且第一位必须是英文字母。
    3、常量。
    数值常量,十进位数字,可以直接作为数值常量。
    字符常量,单个ASC码字符。       
    字符串常量, ASC码字符、汉字区位码字符组成的一串字符。
    4、运算符。
    5、标点符号。
    语句:单词按照一定规则排列起来构成语句。每种语句的语法规则不同,但是除了复合语句之外,必须以分号结束。语句内部数据之间的分隔符,逗号。
    变量:通过语句宣告变量名称和初始值。变量用来储存那些您在稍后的程序程序中还会使用到的值,变量描述的是一种情景的值;变量需要一个处理原始数据的表达式。
    参数:参变量,变量的一种,但是在一定条件下保持不变,对变量结果产生影响的条件值。金语言中参数定义类别属于变量声明的一种。参数被函数调用的,一般后面跟有函数的表达式。是函数的组成部分。
    函数:若干语句组成的一个相对独立功能的程序单元(包含函数类型、函数名、参数表、复合语句),计算结果可以被另外程序调用。
    指标:通过对原始数据进行处理后,具有参考意义的一种函数。
    程序:由数据类型、符号常量、变量的定义,预处理命令行,主程序,若干用户程序组成,具有一定功能的代码。

使用道具 举报

Rank: 3Rank: 3

发表于 2013-8-14 13:58:55 |显示全部楼层
本帖最后由 ptLibert 于 2013-8-14 22:08 编辑

二、数据类型

    数据:人们记录概念、事物、信息的符号,也是程序处理的原始原始材料。

    从数据性质上看,数据有两种类型,一种是数值型,另一种是字符串类型。 数值类型包括整数,浮点数(小数),逻辑真和假;字符串类型使用单引号表示。

    从数据组织上看,上述两种类型分别可以是单值,序列,数组或引用。

    单值是相对序列而言的,如果变量var1是单值,在本K线对var1修改,则前一根K线运算所赋给var1的值将会被覆盖,不再保留; var1是序列,那么,前一根K线运算所赋给var1的值可以通过var1[1]来获得,也可以修改。

    序列是对应K线图上的K线根数而言的,100K线时,序列变量var1就有100个值,每个值对应1K线, 分别是 var1[0], var1[1] ... var1[99],这是对序列数据的编号的格式。序列会随着K线的增加而自动增长,开销要比单值大, 所以如果不需要引用非当前根K线的值时,使用单值变量就足够了。

    数据序列。因为每一个时间周期(每K线)都包含了一个或一组原始数据,如开(开盘价)、高、低、收、量、额。许多周期的数据先后排列组成数据序列。

    序列变量格式:变量:表达式

    例:

  1. k1:open>close
复制代码

    例:指标1High+Low)/2; 每个时间周期的最高值和最低值的平均值输出成指标1

    数组可以看作是固定长度的序列,有固定的大小,由用户在声明时设定。数组不会随着K线增长而增长,跟K线没有一一对应的关系。下面的例子定义了两个数组

   

  1. variable:
  2.     NumericArray aa[100](0),
  3.     NumericArray bb[20, 20](0);
复制代码

    aa大小为100 bb大小为400,都是数组的下标、脚标(a1)。数组的读写使用下标来进行:

    一维数组aa的有效下标:aa[1], aa[2], aa[3] .... aa[100]

    二维数组bb的有效下标:bb[x,y]; x=1,2...20; y=1,2....20;

    引用类型使用于函数的参数传递。就是给参数赋值。一般参数传递是数据拷贝的传递。例如把变量cc原始数据传给函数时,只是传递cc的值,函数内部对它(数据)的修改并不会影响cc原始数据。但当参数类型是引用时,是把变量cc原始数据的地址传递给函数,函数内部对它修改就是对变量cc原始数据的修改

    综上所述,数据类型主要有以下8种:


单值


序列


数组


引用


数值


NumericSimple


NumericSeries


NumericArray


NumericRef


字符串


StringSimple


StringSeries


StringArray


StringRef


    1NumericRef,声明公共函数的输入参数为引用序列。引用序列可以任意改变其中的单个值,并且把改变带到函数之外。

    例如,函数myFunc是这样的。

   

  1. Input:
  2.     NumericRef  P1; //参数声明,分号结束
  3.     P1:=c; //不可能修改它?
  4.     //主程序
  5.     variable: numericSimple x(0);
  6.     myFunc (x);
复制代码

    调用函数myFunc(x)之后,x变成跟c一样

    上面是官方的解释。咋一看懂了,实际没搞懂。太难理解:X何去何来?谁被改变了?改变原始数据,可不可以改变C。谁的地址给了谁?

    个人理解:引用类型数据存在的前提,有两个函数,一个是主函数,一个是被引用函数。myFunc是一个被引用函数函数名,P1是其引用型参数。X是主函数变量。引用型参数,含义是没有自己的“厂房、库房”、没有初始值,只有一个张贴栏、书签,可以记录点东西。一旦调用被引用函数,就必须通过主函数的自变量给被调用函数参数赋值,但是引用型参数没有厂房,他不接受赋值,反而读取主函数变量的地址,在变量的厂房内工作,鸠占鹊巢。现在主函数变量的工厂被被引用函数的参数用来工作室。被引用函数运算时,其参数值被运算改变,则主函数自变量的值也随之被改变了。实际上主函数变量输入初始数值,最后返回被调用函数修改。

    2StringRef,声明公共函数的输入参数为引用字符串。可以在函数中改变引用字符串的值,并把改变带到函数之外。例如,函数myFunc是这样的:

   

  1. Input: //参数声明
  2.     StringRef P1;
  3.     P1:='haha';
复制代码

    调用函数myFunc(x)之后,x的值变成'haha'

    3Invalid,代表无效数据。当一个数被赋值为无效时,图上将不会显示它的值。 如:

  1.     c1:iif(c>o,c,invalid);
复制代码

    那些为invalid的点不画,并且有效的点会连起来。

    c1:iif(c>o,c,invalid),NoDrawInvalid;

    那些为invalid的点不画,有效的点碰到无效点不连起来

    对无效数据的判断:当某个值,假设是x,为无效时,x 不等于 x 。也就是说 x != x 为真。例子:

    bb:RefData( '', D_CLOSE, P_DAY, 0 );//获取某股票日线收盘价,序列数据

    if(bb[DataCount-1]!=bb[DataCount-1] )then Comment('yes'); // bb[],序列数据的编号。不懂,两次校对吗!

    else

    Comment('no'); //在走势图左上角显示

    无效值在dll中如何表示?通过以下来表示:

    std::numeric_limitsfloat::quiet_nan()

    函数解释:

    (1RefData,引用指定商品的指定周期的行情历史数据。RefData(Symbol, DataType, Period, bAlign , nCount) 返回引用数据。

    参数:

    Symbol:品种代码,格式为'000001'或者'000001.SZ'

    DataType: 引用的数据类型,取以下值之一:D_CLOSE, 收盘价;D_OPEN, 开盘价;D_HIGH, 最高价;D_LOW, 最低价;D_VOLUME, 成交量;D_AMOUNT, 成交额;D_OPENINT, 持仓量。

    Period:引用数据的周期类型:Default,当前周期;P_TICK, 分笔;P_MIN1, 1分钟;P_MIN5, 5分钟;P_MIN15, 15分钟;P_MIN30, 30分钟;P_MIN60, 60分钟;P_HOUR1, 1小时;P_HOUR4, 4小时;P_DAY, 日线;P_WEEK, 周线;P_MONTH, 月线;P_QUARTER, 季线;P_HALFYEAR, 半年线
    P_YEAR,
年线

     “对于多分钟线,可使用这样的表示方式n*P_Min1n*P_Min5;例如,3分钟可以用3*P_MIN1表示,15分钟可以用3*P_MIN5表示。

    nCount 是用于逐根并且不对齐模式下的填写数据数量,用于优化执行效率,默认300,该参数不影响逐行模式和对齐的逐根模式

    Align:对齐。1表示对齐,0表示不对齐。当对齐时,长周期数据扩展其数量与短周期一致。
    例如:在1分钟引用5分钟数据,则每根5分钟数据都复制4份,共5份,以便与1分钟K线时间对齐。

    应用实例:

     RefData('600001', D_CLOSE, P_MONTH); //引用邯郸钢铁的月线收盘价

    RefData( '', D_Close, 3*p_min1, 1);//引用本品种的3分钟线收盘价

    (2DataCount,返回序列数据数量。注意:该函数返回常数。从第一根K线到最后一根K线总共的周期数(也就是K线根数)。与barscount的区别:显然,barscount是一个序列变量,随K线的位置不同而不同。而datacount是一个常量,不管在哪个K线的位置上,它都是同一个数值。

    (3P_DAY,日线。

    4、逻辑值。True 真,值为1False 假,值为0。引申为条件成立为1,不成立为0.

    逻辑值是可以赋值的。A:=C>O,我们取义判断是否阳线,计算机及软件处理不是这个意思,他是以每根K线进行逻辑判断,组成一个全由01组成的序列数值型数据。 1表示阳线,0表示不是阳线。这个序列数据,给每根K线增加一个属性。

使用道具 举报

Rank: 3Rank: 3

发表于 2013-8-14 14:05:03 |显示全部楼层

三、操作符

四则运算操作符

操作符

含义

+

算术相加,也可用于字符串想加,字符串+字符串=字符串,字符串+数值=字符串,数值+字符串=出错

-

算术相减

*

算术相乘

/

算术相除

**

算术乘方

++

算术加1

--

算术减1

比较运算操作符、逻辑运算操作符

比较运算操作符

含义

逻辑运算操作符

含义

>

大于

And

逻辑与,也可写作 &&

>=

大于等于

Or

|

<

小于

Not

逻辑非,也可写作 !

<=

小于等于

==

相等,也可写作 =

!=

不相等,也可写作 <>

位运算操作符、赋值操作符

位运算符

含义

赋值操作符

含义

<<

向左位移

=

赋值

>>

向右位移

+=

a += b 含义是 a = a + b

&

位与 (均11

-=

a -= b 含义是 a = a - b

位或 (有1便1

*=

a *= b 含义是 a = a * b

~

位非 (取反)

/=

a /= b 含义是 a = a / b

^

位异或 (相反才1

&=

a &= b 含义是 a = a & b,位与

=

a = b 含义是 a = a b

^=

a ^= b 含义是 a = a ^ b

<<=

a <<= b 含义是 a = a << b

>>=

a >>= b 含义是 a = a >> b

位非:取反。运算符查看表达式的二进制表示法的值,并执行按位非操作。表达式中的任何一位为 1,则在结果中相应位变为 0。表达式中的任何一位为 0,则在结果中相应位变为 1。该操作的结果如下所示:

0101   (expression)      1010   (result)

位或  按位或运算符“|”是双目运算符。其功能是参与运算的两数各对应的二进位相或。只要对应的二个二进位有一个为1时,结果位就为1。参与运算的两个数均以补码出现。

例如:9|5可写算式如下:

00001001|00000101   00001101 (十进制为13)可见9|5=13

位与   按位与运算符"&"是双目运算符。其功能是参与运算的两数各对应的二进位相与。只有对应的两个二进位均为1时,结果位才为1 ,否则为0。参与运算的数以补码方式出现。

例如:9&5可写算式如下:

00001001 (9的二进制补码)&00000101 (5的二进制补码) 00000001 (1的二进制补码)可见9&5=1

位异或  按位异或运算符“^”是双目运算符。其功能是参与运算的两数各对应的二进位相异或,当两对应的二进位相反时,结果为1。参与运算数仍以补码出现,例如9^5可写成算式如下:

00001001^00000101 00001100 (十进制为12)

使用道具 举报

Rank: 3Rank: 3

发表于 2013-8-14 14:05:59 |显示全部楼层

四、变量

变量是一个标识符,读入一个或一组原始数据进行加工的容器,公式(程序)可以通过该标识符对变量数据进行读取或赋值。其实就是数学概念Y=FX)中的自变量X。变量的类型可以是数值类型或字符串类型;变量可以是数组,序列或单值。

变量和数据的关系:水和水桶的关系。

变量的组成:可以作为变量名的字符是 数字 0-9,字母 A-Z 特殊符号 _ % $ 和汉字,变量不能以数字开头,变量的长度没有限制,变量的字母不区分大小写(DLL调用的函数声明除外,此时是区分大小写的),已经作为内部函数,公共函数和关键字的标识符不能作为变量。

变量声明:变量使用的时候必须说明,变量默认为系列变量。并且初始化。保留字variablevariablesNumericSimpleArrayIntraBarPersist,声明并初始化变量。语法:

变量声明保留字:变量名1(初始值),变量名2(初始值),.....;

1VARIABLE:varname1(initValue1),varname2(initValue2),.....;

varname1,变量名。initValue,变量的初始值,变量无默认值、最大值、最小值。

例如:

variable: numericSimple x(1), y(CLOSE), ARR[10](0), SARR[5]('str');

表示定义单值变量x并初始化为1;申明序列变量(默认)y并初始化为收盘价;申明含10个浮点数的数组并全部初始化为0;申明含5个字符串的数组并都初始化为'str'

variable: NumericSimple SN(90), V1(0), V2(0);

SN是单值变量,不占内存,而V1V2是序列变量。

NumericSimple的优势是资源占用小,效率高。而序列变量多数情况下可兼容单值型变量,所以默认是序列变量.

2VARIABLES:varname1(initValue1),varname2(initValue2),..;

VARIABLESVARIABLE语法相同。

3NumericSimple,声明变量为单值变量。语法:

variable:NumericSimple SN(90),V1(0), V2(0);

SN是单值变量,不占内存,而V1V2是序列变量。

NumericSimple的优势是资源占用小,效率高。而序列变量多数情况下可兼容单值型变量,所以默认是序列变量。

4array,数组。语法:

Array:IntraBarPersistArrayName1[D1,D2,D3,etc.](InitialValue1,DataN), IntraBarPersistArrayName2[D1,D2,D3,etc.](InitialValue2,DataN),etc.Arrays

arrayA[10](0);

VARIABLE(或VARIABLES)A[10](0);

2种定义相同,第2种定义是为了兼容飞狐。

A[10] 是整个K线序列只有一个11个元素的数组,下标从0-10

5IntraBarPersist,记住每笔,指定了这个修饰的变量,会记住上一个tick的值。没有指定,则记住上一个bar的值。变量修饰符,必须配合run_every_tick开关使用。没有指定run_every_tick时,则intrabarPersist的修饰不会生效。

#run_every_tick

variable:

intrabarPersist numericSimple x(0), intrabarPersis y(0);

6DLL函数各种变量声明:

1)、extern,声明DLL函数。例:

extern 'foxfunc.dll' void myfunc( NumericSeries resultArray, NumericSeries array, int n);

extern 'dllname' ,此处的dllname,可以是一个url地址(可以是dllzip压缩文件),例如:

extern 'http://www.hs633.com/fmldll/Position.zip' extern 'http://www.hs633.com/fmldll/Position.dll'

2)、LpcwStr,声明DLL函数unicode字符串指针。例:

extern 'FoxFunc.dll' void myStrFunc(LPCWSTR str1);

3)、Dword,声明DLL函数双字无符号整型变量。

Double,声明DLL函数双精度浮点型变量。

Char,声明DLL函数字符型变量。

Int,声明DLL函数整型变量。

Float,声明DLL函数浮点型变量。

Long,声明DLL函数长整型变量。

例:

extern 'FoxFunc.dll' double myfunc(char d1, int d2, long d3, DWORD d4, float d5, double d6, bool d7, ulong d8);

4)、Void,声明DLL无返回值函数。例:

extern 'FoxFunc.dll' void myStrFunc(LPCSTR str1);

5)、LpcStr,声明DLL函数字符串指针。例:

extern 'FoxFunc.dll' void myStrFunc(LPCSTR str1);

7Const,常数。const:ConstName1(InitialValue1), ConstName2(InitialValue2),.....;

8Arrays,数组,

Arrays:IntraBarPersistArrayName1[D1,D2,D3, etc.] (InitialValue1 ,DataN),IntraBarPersistArrayName2[D1, D2,D3 ,etc.](InitialValue2,DataN),etc.Arrays

特殊变量,指标的表达式输出的数值,没有变量声明,可以通过指标名加引号来使用,如"FENG2.HD",而且直接当作序列变量来使用,参与到别的运算,切记不要不当着字符变量来理解。

变量用来干什么?

变量就是个赋值传送带。晕死!

X>CLOSE

X=CLOSE

你怎么理解。怎么运行!比如CLOSE=10201518等。

使用道具 举报

Rank: 3Rank: 3

发表于 2013-8-14 14:06:26 |显示全部楼层
五、中间变量
中间变量(也可称为临时变量),是用“:=”来定义的,而变量(即序列变量)的定义是用“:”。中间变量的结果,不会在K线图的主图或副图中显示出来。实际上中间变量在计算机内部是当做函数一样是生成一个序列函数值。
例5:设计一个副图指标,8日内如果先后出现5日均价线上穿10日均价线、5日均价线上穿20日均价线,则返回1,否则返回0。
那么本例是不是可以写成:
cross(ma(c,5),ma(c,10)) and cross(ma(c,5),ma(c,20))
答案是否定的。因为这个条件表达式是表示同时满足2个条件,而不是先后。本指标的设计要用到逻辑函数“是否存在”EXIST(X,N)。
EXIST(X,N):返回N周期内是否存在满足条件X,N可为常数或变量,可以EXIST(X,N) and EXIST(X,N)若N=0则从第一个有效值开始。例如: EXIST(C>O,10)表示10个周期中存在阳线}。正确代码结果如下,我们把公式命名为sl003:
信号:EXIST(cross(ma(c,5),ma(c,10)),8) AND EXIST(cross(ma(c,5),ma(c,20)),8)
代码说明:本例中,公式代码使用了函数嵌套,即一个函数套一个函数,这里使用了三重嵌套。
要看懂嵌套函数,基本的分析方法是,从里到外一层层分析,如EXIST(cross(ma(c,5),ma(c,20)),8),先分析ma(c,5)、ma(c,10)是什么意思,然后分析cross(ma(c,5),ma(c,20))是什么意思,最后再分析EXIST(cross(ma(c,5),ma(c,20)),8)是什么意思。
考察上面的示例公式sl003中,ma(c,5)共出现了2次,每出现一次,软件都要进行一次5日均价的运算,要重复算2次相同的运算。如果一个公式中,类似这样ma(c,5)出现的次数是N次,那岂不是要重复N次相同的运算,是不是有点太“笨”了?效率太低了?解决的办法是,把运算结果先“存”到中间变量,要用时,从中间变量中取出。
例5的公式,条件满足时,指标线的值会由0突变为1,“信号”很醒目。不过还是有点不爽,如果连续出现信号则第一次满足条件才给出“信号”,似乎更好些,怎么办呢?
提示:①利用“引用函数”类中的“信号过滤”函数FILTER(X,N):将满足条件后N周期内的数据置为0 。例如:FILTER(CLOSE>OPEN,3) ;查找阳线,3天内再次出现的阳线不被记录在内②巧妙利用“突变”这个特征。
例6:选用适当的中间变量,改写公式sl003。
求解:正确结果如下,我们下面公式命名为sl004
n:=8;
ma5:=ma(c,5);
ma10:=ma(c,10);
ma20:=ma(c,20);
tj1:=EXIST(cross(ma5,ma10),n);
tj2:=EXIST(cross(ma5,ma20),n);
信号:tj1 and tj2;
代码解释:①ma5:=ma(c,5)是中间语句,ma5是中间变量, ma10、ma20、tj1、tj2、n也是中间变量,想想看公式代码中,“信号”是中间变量吗?②公式代码中,n:=8,不是为了减少运算量,这里使用中间变量的目的,是为了改写代码方便,例如,公式设计好后,发现用8不大妥,想写为9,于是就需要在代码中找若干处把8改写为9,用中间语句n:=8,则公式代码只需修改一处就行了。

使用道具 举报

Rank: 3Rank: 3

发表于 2013-8-14 14:06:55 |显示全部楼层
六、参数、参数精灵
我们再来新建一个公式SL002,代码如下:
ma5:ma(close,5);{可以省略指标名简写为ma5:ma(c,5);}
代码解释:定义了一个序列变量ma5,其序列值由函数ma(close,5)确定。
Ma,求简单移动平均。用法: MA(X,N),求X的N日移动平均值。算法:(X1+X2+X3+...+Xn)/N。
例如: MA(CLOSE,10)表示求收盘价10日均价
显然,ma5被定义为5日均价,在K线图中,切换股票到600004,敲sl002,调用这个公式,观察5日均价曲线,发现ma5是从第5根K线开始的,也就是说,ma5的起始有效周期是5。根据ma函数的定义,ma5即ma(close,5)等于当日及前4日收盘价的算术平均值,至少要有5天的数据,这就是说,从第5天开始,才会有5日均价。
下面,我们修改刚才建立的公式sl002,代码如下:
ma5:ma(close,5);
ma10:ma(close,10);
ma20:ma(close,20);
ma30:ma(close,30);
ma60:ma(close,60);
注意,每一行公式代码的末尾要有一个半角的分号“;”,表示一行代码结束。切换股票到600317,观察我们修改后的sl002显示的结果,原来就是我们所熟悉的均线系统,由5、10、20、30、60日均价线组成。
上面修改后的公式sl002,已经是很实用的公式了。但有个缺点,如果你想要的不是5、10、20、30、60日均价线,而是其它的譬如7、14、21、28、35日的均价线,怎么办?修改公式代码是一个可行的办法,但太麻烦。可以使用参数,把公式sl002修改如下:
ma5:ma(close,n1);
ma10:ma(close,n2)
ma20:ma(close,n3);
ma30:ma(close,n4);
ma60:ma(close,n5);
在公式编辑器中,输入参数n1----n5的最小、最大、缺省值(就是参数实际取值)。
结果发现,公式sl002显示跟原来一样没有变化。右键点击图上公式名sl002,选择调整修改参数,一边观察指标线是否变化。可见使用参数的意义在于修改参数,不用修改代码达到我们的目的。
参数的加深了解:
1、使用参数的目的就是不去改动代码,通过参数精灵渠道设置。
2、公式的参数是一种特殊类型的变量,是我们设计程序的时候,留的接口,用户可以外部通过界面设定该变量的值。也是主函数和局部函数之间数据传输的通道。参数的类型只能是单值变量NumericSimple和字符串String。
3、MA(X,N)中X、N是MA的参数。ma(close,n1)中n1也是参数,到底怎么了解合适!X、N是通用函数的参数位,没有X、N,n1没得法存在。n1的存在是在同一程序中可能多次使用该函数,为了区别不同语句中该函数的参数,以n1、n2区分。n1、n2实际上是个另外一种意义上的变量,以变量作为参数。X、N位置,如果输入常量,该常量也是参数,但是不能通过参数精灵渠道设置。
4、参数必须有默认值,参数是变量例外。
参数使用要声明,并设置。半角分号结束。保留字:INPUT、String、NumericSeries、StringRef、NumericRef、Numeric。
1、INPUT: pname1(dft,min,max,step), pname2(dft,min, max, step) ...;
pname表示参数名, dft表示缺省值,min表示最小值,max表示最大值,step表示优化步长,除default外都可省略。如:
INPUT:N(5), M(10,1,100,2);
表示定义参数N,缺省值为5,定义参数M,缺省值为10,最小值为1,最大值为100,优化步长为2。
2、String,声明公共函数的输入参数为字符串。Input: String P1;
3、NumericSeries,声明公共函数的输入参数为序列。序列能够通过下标访问其中单个元素。Input: NumericSeries P1;
4、StringRef,声明公共函数的输入参数为引用字符串。可以在函数中改变引用字符串的值,并把改变带到函数之外。例如,函数myFunc是这样的 :
Input: StringRef P1;
P1:='haha';
调用函数myFunc(x)之后,x的值变成'haha'
5、NumericRef,声明公共函数的输入参数为引用序列。引用序列可以任意改变其中的单个值,并且把改变带到函数之外。例如,函数myFunc是这样的
Input: NumericRef P1;
P1:=c;
调用函数myFunc(x)之后,x变成跟c一样。
Numeric,声明公共函数的输入参数为数值型。用于传入单值。Input: Numerice P1;
6、参数精灵:是公式的一种说明描述,显示在调整公式参数面板上。
参数精灵通过 Param#No 或 SParam#No 来对应参数的类型和第几个参数,Param是数值型,SParam是字符串类型。注意它们是大小写敏感的,No是数字,代表第几个参数。
在上面修改参数的过程,是否注意到参数的提示?因为公式是自己设计的,参数的提示尽管很简单,但自己仍然知道参数的含义,但如果是其他人的话,就可能摸不着头脑了,因此有必要对参数加上一点提示。方法是,在公式编辑器中,点“参数精灵”按钮,输入以下文字:
Param#1日均价(1--999);
Param#2日均价(1--999);
Param#3日均价(1--999);
Param#4日均价(1--999);
Param#5日均价(1--999);
也可以用代码设置参数精灵,替代点击按钮“参数精灵”。保留字是#TEMPLATE。
7、TEMPLATE ,参数精灵代码设置。用在input之前,输入参数说明。
#TEMPLATE
'统计主动性卖盘成交量大于Param#1股的成交量总和'
INPUT:
M(10000,1,100000);
SUM(IIF(SELLVOL>=m,VOL,0),0)
SELLVOL,取得主动性卖单量。SELLVOL 当本笔成交为主动性卖盘时,其数值为该笔成交量,否则为0 (本函数仅个股在分笔成交分析周期有效)。

使用道具 举报

Rank: 3Rank: 3

发表于 2013-8-14 14:07:23 |显示全部楼层
七、语句
单词按照一定规则排列起来构成语句。每种语句的语法规则不同。一条语句可以是一行,可以是多行,不论是一行还是必须是多行,分号之前都是该语句的一部分。但是除了复合语句之外,必须以半角分号结束一条语句。金语言语句分类没有官方分类。
1、定义语句:数据类型说明、变量说明、参数说明语句。
表达式语句:运算表达式。如赋值、比较等。
2、复合语句:用BEGIN END包含的语句。复合语句是一条语句,把多条语句看作一条语句。BEGIN END后面不要分号,BEGIN END之间的语句要分号。
3、循环语句:FOR、REPEAT、WHILE、BREAK、CONTINUE
(1)FOR,循环语句。语法: FOR var=n1 TO n2 DO expr;从 var=n1 开始到 var=n2 开始循环执行 expr 语句,每执行一次var加1。FOR var=n1 DOWNTO n2 DO expr2;从 var=n1 开始到 var=n2 开始循环执行 expr 语句,每执行一次var减1。
for i = 1 to 100 step 10 do begin//step循环语句步长默认为1
x := x + 5;
end
(2)REPEAT,循环语句。语法:REPEAT expr1 UNTIL cond ;循环执行语句 expr1直到cond 条件满足。
(3)WHILE,循环语句。 WHILE cond DO expr ;当满足 cond 条件的时候,循环执行语句 expr。
(4)BREAK跳出循环。语法:BREAK;
(5)CONTINUE,继续循环。
4、分支语句: SWITCH CASE
SWITCH,多分支条件语句。当express等于不同的case值时,执行不同的动作”。语法:
switch ( expression ) begin
case constant-expression : statement
case constant-expression : statement
...
[default : statement]
end
用法:例:
switch( x ) begin
case 1: a:=20;
case 3: a:=50;
case 100: a:=H;
default: a:=c;
end
当x等于1时a赋值20,当x等于3时a赋值50;当x等于100时a赋值最高价,其他的a赋值收盘价。
5、条件语句:设计公式,需要大量使用条件表达式,根据条件表达式的结果,作出判断,以便确定下一步该做什么,不该做什么。基本的条件表达式由“>、>=、<、<=、=、and、or、not”等比较运算符、逻辑运算符组成,此外单独的“逻辑函数”如“是否最后周期ISLASTBAR”也可以构成条件表达式。条件表达式的值只有2个,1和0,是则返回1,不是则返回0。
IF条件语句,IF cond THEN expr1 ELSE expr2。满足 cond 条件的时候,执行语句 expr1,否则执行 expr2 语句。请把序列相关运算写在条件判断的前面,否则应当在所有的分支都被赋值。例如,以下写法是不对的。
if(not 交易联通()) then 退出;
买信号 :=cross( ma(c,5),ma(c10);
Buy(...);
请改为:
买信号:=cross( ma(c,5),ma(c10);
if(not 交易联通()) then 退出;
Buy(...);
Iif,条件函数,根据条件取不同的值。IIF(X,A,B)若X不为0则返回A,否则返回B 。例如:IIF(CLOSE>OPEN,LOW,HIGH);表示该周期收阴则返回最低价,否则返回最高价。
例1:close>open{表示收盘价大于开盘价,如果成立返回1,否则这个条件表达式的值为0};
例2:close>open and close>ma(close,5){表示收盘价大于开盘价且close大于5日均价,and 是“且、和”的意思};
例3:close<=ref(close,1) or close<=ref(close,2){今收盘小于昨收盘或今收盘小于等于前2天收盘价,or是“或 的意思,ref函数向前引用,REF(X,A),引用A周期前的X值};
例4:corss(ma(c,5),ma(c,10)){5日均价线上穿10日均价线,cross函数的定义,CROSS(A,B)表示当A从下方向上穿过B时返回1,否则返回0。这里close简写为c};
6、坐标定义语句:REFLINE。
REFLINE,指定在哪些位置画水平坐标线。RefLine:l1,l2,l3...指定在哪些位置画水平坐标线,最多可设置7个,用分号分隔。
例如对MTM,可以输入'#RefLine:-0.6,0,0.6'。系统将显示在这三个数值的水平坐标线。仅对副图指标有效。如果没有指定RefLine,那么缺省时系统按实际值设定最佳显示的水平坐标线。”
7、交易语句:BUY SELL SELLSHORT BUYTOCOVER
8、指标输出语句:指标名:表达式(,线形描述)* plot语句 print comment
(1)Plot,根据设置参数输出、绘制指标值。
例子: Plot( c, 'theclose' , COLORBLACK, ColorYellow, 3, circleDot)  Plot[30](c); //画一条收盘线并向左偏移30根K线。
(2)X:输出的序列变量或数值
9、注释语句。公式编写中,往往需要插入描述性文字,这些文字在编译时是忽略的,不会被运行。
//  单行注释
{}段落注释
在公式编辑器里,注释呈现绿色。

使用道具 举报

Rank: 3Rank: 3

发表于 2013-8-14 14:07:51 |显示全部楼层
八、函数
函数包括:是一些会反复使用到的功能,封装而成的一段代码。函数代码由函数声明、变量声明、参数声明、运算表达式、注释描述等语句组成。如果运算表达式只引用内置函数进行运算,则不存在函数声明。
函数运算表达式的基本格式: 变量名:运算表达式。
函数类型,根据是否保留字划分为系统预定义或用户自定义类型。
系统预定义函数,程序、函数代码中可以直接使用其保留字进行引用。也可以通过新建公式面板中插入函数进行引用。
如:指标名:close;
用户自定义函数:需要先定义才能使用。所谓使用自定义函数,是指引用一个函数的程序模块,而不是指引用一个变量。声明函数语句中不需要设置参数。引用自定义函数时只须:函数名(参数)。多数代码中没有自变量,或者说自变量是时间。
FUNCTION,自定义函数,需要先定义才能使用。例如:
Function ShowMsg //定义自定义函数ShowMsg,不用分号,不涉及参数
Input: condition(0); //声明参数,0是参数缺省值
Begin //自定义函数的主体开始,不用分号
If condition > 0 then  print('高开')  else if condition 〈 0  print('低开');
End //自定义函数的主体结束,不用分号
show(OPEN > close[1]);//官方解释不懂这句干嘛
函数类型,根据函数存放位置划分为:内置函数、局部函数和公共函数。
内置函数是最常用的函数,本软件中有很多内置函数,例如ma、hhv、buy、sell等等。在公式编辑器的字典内可以查阅。当内置函数不够用,除了等待软件升级新增所需函数,还有一个途径,就是通过公式语言自行编写局部函数或公共函数。
金语言编写的函数有两种存在形式:局部函数和公共函数。局部函数和公共函数仅工作于逐根模式下。
局部函数:内嵌在其主程序中的一段函数代码。例1:
//以下函数把上次传入的点和这次传入的点用线连起来。每隔10根k线,就在收盘价处连一条线
function drawl //自定义函数drawl开始
input: numericSimple var1; //参数声明,参数是个变量
variable: numericSimple d0(0),t0(0),v0(0); //变量声明
begin //自定义函数主体开始,无分号
  if( d0!=0 and date>2013 )then begin  id = tl_new( d0, t0, v0, date, time , var1); //不懂,date应该是year吧。Id趋势线编号?先后两个K线的收盘价。d0, t0, v0定位K线。v0、var1、close确定高度。
  end;
  d0 = date; //赋值
  t0 = time; //赋值
  v0 = var1; //赋值
end//自定义函数结束,无分号
//主程序体
//每隔10根k线,就在收盘价处连一条线
#run_by_bar //无分号
#MainChart //无分号,该指标被双击时默认显示到主图上
#nodefaultoutput//?无分号
if( barpos mod 10 =0 )then // K线序号整除求余为0,
  drawL( close ); //调用局部函数,输出合符条件值的给局部函数的参数var1:10,20,30,40.50…..K线的收盘价。
函数解释:
(1)tl_new,新建趋势线。返回所创建趋势线的唯一数字标识号,从0开始计数,用于将来的读取与设置。TL_New (sDate, sTime, sPriceValue, eDate, eTime, ePriceValue) 。参数:
sDate: 起点日期,格式为YYYMMDD;
sTime: 起点时间,格式为HHMMSS
sPriceValue: 起点数值
eDate: 终点日期
eTime: 终点时间
ePriceValue: 终点数值
(2)date,取得该周期开始时,从1900以来的年月日。函数返回有效值范围为(700101-1341231),表示19700101-20341231。
(3)YEAR,函数返回有效值范围为(1970-2038)。
(4)BarPos,函数返回当前是第几根K线,从过去某一K线开始计数。对于日线数据就表示从上市到现在(当前K线)总共有多少交易日。
(5)MOD,求模运算。模运算即整除求余运算,A Mod B=A-(A div B) * B (div含义为整除)。MOD(A,B)、A Mod B两种方式返回A对B求模。例如: MOD(18,10)返回8。
(6)#MainChart,该指标被双击时默认显示到主图上。#mainChart
ma(c,5);
输出就会放到主图上
(7)#run_by_bar,逐根模式,说明:1.run_every_bar和run_every_tick,都是针对逐根模式的开关,逐行不支持这两种模式。所以逐行下写这两个开关实际上会被忽略。2.智能交易类公式,系统自动强制run_by_bar模式执行,即使写run_by_serie也会被忽略。3.技术指标里,如果指定run_by_bar模式,那么默认run_every_tick。 run_every_bar,需要指定。
run_every_bar,每根K线只运行公式一次,运行时间是下一根K线的第一笔Tick到来时,交易脚本默认的运行方式。
run_every_tick,每个Tick都会触发公式运行,指标类公式的默认运行方式;
例如:绘制1条趋势线,起点位于2012年8月13日9:00时的2310处,终点位于2012年8月18日14:00时的2380处。如果因日期非法或其他原因画线创建失败,则函数返回-2。
TL_ID1:=TL_New(1120813,90000,2310,1120818,140000,2380);   (TL_ID1,直线名字。)
公共函数:把函数独立出来,其代码单独成为一个程序文件。这样的函数,在其他程序代码里不需要额外的声明就可以直接使用,跟ma等内置函数一样。公共函数是金语言七大公式的一种。存放系统自带或用户自创的公共函数。

使用道具 举报

Rank: 3Rank: 3

发表于 2013-8-14 14:08:16 |显示全部楼层
九、程序
程序,由数据类型、符号常量、变量的定义(如头文件内容),预处理命令行,主程序,若干用户程序组成的代码文件。按结构可以把程序划分为初始化函数、自定义函数、主函数、执行完毕函数几个部分。
初始化函数、执行完毕函数代码是在某些事件发生的时候才触发执行。视为有固定名称OnInit、OnExit的特殊自定义函数。
初始化函数:预处理一些事情。初始化事件会让公式清除所有状态重新运行计算1次,后续行情到来不再计算。只要编写一个内置函数,并且命名为OnInit,那么它就会在初始化时执行。那么,OnInit究竟具体在什么时候会发生呢。 包括并且不限于以下情况,例如:
1.切换成其他品种;
2.切换成其他周期;
3.服务器推送来一些旧的历史数据(某种情况下,可能客户端会先请求最新一段数据,再请求旧的数据)。
fucntion OnInit  //初始化函数声明,做一些只需要做一次,没有必要每次行情来时都做的工作。例如,设置画线的颜色,设置账号。等等。
Begin
  ……
End
执行完毕函数:收尾工作。只要编写一个内置函数,并且命名为OnExit,那么它就会在公式执行到末尾时执行。
function OnExit
Begin
   ……//做一些收尾工作
End
为什么需要OnExit呢,是因为目前公式引擎支持“中断”。所谓中断,就是如果某些公式计算一次时间特别长,有时公式运行到一半,还没计算完,用户切换到其他品种了,那之前的计算就没有必要继续下去,这时候,系统就会强行中断计算。
但是,用户可能希望某些计算是必须要执行的,例如,这个公式可能是调用DLL的,DLL可能在开始分配了一些资源,而且必须在运算完毕后释放,这部分计算就可以写在OnExit中,正常情况下它们会在公式主体运行结束之后被执行。如果公式主体被中断,它们会在中断后执行。
自定义函数(略,相当于局部函数)。
程序主体(主函数):主函数是名为OnStart的函数,象这样:
Function OnStart   //相当于自定义一个函数
Begin
mm:ma(c, close );
End
但是,为了方便编写,上述的“Function OnStart”可以省略。也就是可以只写
mm: ma( c, Close );
凡是没有包在其它函数体里面的代码都被认为是 OnStart 函数的内容。除非显式声明了 OnStart 函数。如果声明了OnStart函数,又写了一段没有被任何函数包裹的代码,那么没有被包裹的代码被直接忽略,认为是空白。

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

bottom

Archiver|http://www.patiosoft.com

GMT+8, 2017-12-11 12:39 , Processed in 0.135139 second(s), 10 queries .

花生网 Copyrigh©2012

和讯信息科技有限公司 ALL Rights Reserved 版权所有 复制必究

回顶部