zoukankan      html  css  js  c++  java
  • 量化投资_EasyLanguage/PowerLanguage教学课程__【第一篇基础】__【第六章函数】

    第六章:函数

    第一节:新建函数

    1.1 函数

      所谓函数,就是把一些程序存储成特定的脚本,在使用时,无须重复编写,直接调用,使代码的复用率提高的一种办法,从本质上来说也是一种“脚本”,因此函数需要分建立和调用两个部分。另外,在公式编辑器的导航器可以看到有MC预先编写好的函数、指标和信号,这些预先编写好的脚本我们叫做内置(Bult-in)。一个完整的函数是需要有:输入→函数体→返回值,其中输入我们也叫做参数。

    1.2 新建函数

      再说新建函数的时候,我们首先说一下,在新建脚本的时候会有三种公式类型可以选择,其中有函数、指标和信号。MC与其他软件最大的不同是区分指标和信号的分别建立。也就是说我们看到的一些技术指标,而且想建立这些技术指标的话,我们选择新建指标。如果想利用编写好的指标添加交易逻辑的话,可以选择信号。当然,在MC当中,指标编写中是不允许出现信号买卖的逻辑,但是允许有画图等显示代码,另外,信号编写时,是不允许出现画图这样的指标显示代码的。MC区分开指标和信号的原因是提高代码运行的效率,如果在信号当中添加画图代码势必会造成代码运行的开销,降低下单买卖指令的运算。因此这种做法是好的。

       在新建函数选择框中,可以看到返回类型函数存储形式

      所谓返回值可以选择数值型、TrueFalse(布尔型)、字符串型,也就是我们通过函数的运算,最终想要得到一个什么结果。默认状态下,数值型的返回值是0,布尔型的返回值是False,字符串的返回值是空。函数的存储是因为数列类型(序列型)函数会将函数返回值绑定在当根bar上,后续进行回溯数值,而数值类型函数值只有一个值,不能进行回溯值,对于自动类型函数,默认情况下自动类型函数是数值类型,但是自动类型函数会在某种情况下是数列类型函数,这个是在函数编译时就确定了。这里牵扯到一个在函数体内部自动变换的问题,后面会说到,在此我们默认为“自动”,后面方便观察这个自动变换过程。

    第二节:函数的参数

    1.1 声明

      声明就是在写函数、指标和信号的时候,需要实现对其需要的数组、参数、变量进行的“预定义”,之前见到过的Inputs:、var:、array:分别表示声明参数、变量和数组。这是并不是必须的,但是如果需要更多复杂的逻辑,也是必须使用的。

      另外,在MC当中,对于变量有一些默认的全局变量,分别是:

      数值型:初始值0:有99个,value1~value99

      逻辑性:初始值False,有99个,condition1~condition99

      参数与变量的区别是,变量可以在公式内部改变,而一般的参数只能在程序外部修改(当指标或者信号插入到图表时,可以修改参数是定的初始值);参数可以在外部进行优化,变量不可以;只要声明引用型参数时,才允许程序内部改变参数,且会带有Ref这样的关键字。

      函数的参数也叫函数的输入,在函数当中,声明部分与其他指标和信号一样,在Inputs:定义好想要传入函数参数的类型。

    1.2 IntraBarPersist函数

      这个函数是比较特别的,他是添加在定义变量之前的。

    # 语法

    Declaration:[IntraBarPersist]Name(InitialValue1)

    # 说明

      用在变量和数组的声明语句中,在变量或数组名称之前,用来指定变量或数组元素的值依据每根tick更新。如果没有指定的话,变量或数组值将会在每根Bar的close更新。

    # 示例

    声明一个数值型变量 Max,按照每 tick 更新,初始值为 100:
    Variable:IntraBarPersist Max(100);
    声明一个含 24 个元素的一维数值型数组 Max_Price,元素值按照每 tick 更新,元素初始值为 0:
    Array:IntraBarPersist Max_Price[23](0);

     1.3 定义函数参数、变量类型

      与变写指标和信号最大的不同。在指标和信号中,声明可以设定默认值,或者不写。例如:var:var0(0);,括号内的值我们是可以填写具体的值(数值、布尔、字符串)。但是函数做为一个需要接收这些值的代码。对于括号内的具体值一般是不知道的。因此我们需要在这个括号内定义需要接收某个值的类型。根据数值的类型:数值型、字符串型、布尔型(基本数据类型);序列型、数组型、引用型(特殊数据类型),可以如下表:

      数值:

      Numeric  

      NumericSimple

      NumericSeries

      NumericRef

      NumericArray

      NumericArrayRef

      布尔型:

      TrueFalse  

      TrueFalseSimple

      TrueFalseSeries

      TrueFalseRef

      TrueFalseArray

      TrueFalseArrayRef

      字符串型:

      String  

      StringSimple

      StringSeries

      StringRef

      StringArray

      StringArrayRef

       为了防止重复解释,我们只观察后缀:

      1、不带后缀的:表示为数值型。它可以是简单数值(Simple)或者序列数值(Series)。简单数值不能进行回溯(也就是在当前位置不能去前面某个位置的K线数值),序列数值是从Bar到Bar的变化,可以回溯历史。

      2、Simple:设定好为简单数值

      3、Series:设定好为序列数值

      4、Array:声明一个数组类型;在这里提示一下语法应用:

    Input:InputName[M1,M2,M3,etc.](NumericArray)
    
    参数:
    InputName——表达式,指定 input 参数的名称。名称可以包
    括英文字母、下划线、数字和英文句号。字母不区分大小写,名称不能用数字或下划线开头。
    M——变量,表示传递到函数的数组每个维度的最大索引值,一个变量指定的是一维数组,两个变量指定的是二维数组(M1,M2),三个变量指定的是三维数组(M1,M2,M3)以此
    类推。
    一个 input 声明只能是一个指定维度的数组。

      要说明的是一般声明的时候,用X变量来指定数组的最大索引值

      # 示例

    声明 Length 作为函数的一维数值数组参数:
    Input:Length[X](NumericArray);
    数组的最大索引值由变量 X 来指定。
    声明 Table 作为函数的一个三维数值数组参数:
    Input:Table[X,Y,Z](NumericArray);
    数组的最大索引值由变量 X,Y,Z 来指定。

       5、Ref:引用型;所谓引用型是运行在函数脚本中对参数进行变更,并且在外部可以直接调用这个修改后的值。换句话说,也就是给函数传递这个变量,不光可以传递值,而且在外部可以接收这个值。一般在声明成布尔类型的函数经常采用这种方式,后面会举例说明。

    第三节:序列参数与简单参数的区别

      这个部分可能是函数这块儿的一个小难点。我们发现在前面有不带后缀的声明,诸如:Numeric,再就是带有Simple和Series后缀的声明。后面两个根据前面的定义来说一个是简单型,一个是序列型。

      现在,我们先分别定义好这两个参数,观察一下,他们是否可以进行回溯操作:

    3.1 区别1:定义成Simple只是简单变量,而定义成Series是可以回溯

    # 示例1:观察Simple和Series,是否可以回溯

    //func
    
    input: simple(numericsimple), series(numericseries);
    
    print("func ,","simple=",simple,",simple[1]=",simple[1],",series=",series,",series[1]=",series[1]);
    
    //indicator
    
    var: var0(0), var1(0);
    
    var0=currentbar;
    
    var1=currentbar;
    
    print("sign ,","currentbar=",currentbar);
    
    func(var0,var1);
    
    //print输出结果
    
    sign ,currentbar=   3.00
    
    func ,simple=   3.00,simple[1]=   3.00,series=   3.00,series[1]=   2.00
    
    sign ,currentbar=   4.00
    
    func ,simple=   4.00,simple[1]=   4.00,series=   4.00,series[1]=   3.00

    # 说明:通过返回值我们可以观察到。在定义成简单型Simple的情况下,它仅仅是一个变量值,没有产生回溯的效果,回溯前一个值并不起作用。也就是说:定义成Simple只是简单变量,而定义成Series是可以回溯

    3.2 区别2:函数内部自动变化成序列类型。

    # 示例2

    //func
    
    input: num1(numeric), num2(numeric);
    
    print("func ,","num1=",num1,",num2[0]=",num2[0]);
    
    //indicator
    
    var: var0(0), var1(0);
    
    var0=currentbar;
    
    var1=currentbar;
    
    print("sign ,","currentbar=",currentbar);
    
    func(var0,var1);

    # 说明:在这个例子中,并不特别指明是Simple还是Series。通过返回值观察到,num2被强制变换成序列类型了。这是因为在没有特别声明具体是哪一种类型的情况下,在函数体内部如果使得变量具有序列性质(也即是带方括号[0],这个样子),MC系统会自动的帮我们转换成序列参数。

    3.3 区别3:外部传入序列类型变量至函数内,使simple类别变为series类型

    # 示例3:

    //func
    
    input: simple(numericsimple), series(numericseries);
    
    print("func ,","simple=",simple,",simple[1]=",simple[1],",series=",series,",series[1]=",series[1]);
    
    //indicator
    
    var: var0(0), var1(0);
    
    var0=currentbar;
    
    var0[0];
    
    var1=currentbar;
    
    print("sign ,","currentbar=",currentbar);
    
    func(var0,var1);
    
    //print输出
    
    sign ,currentbar=   3.00
    
    func ,simple=   3.00,simple[1]=   2.00,series=   3.00,series[1]=   2.00
    
    sign ,currentbar=   4.00
    
    func ,simple=   4.00,simple[1]=   3.00,series=   4.00,series[1]=   3.00

    # 说明:同案例1,当时我们回溯simple值的时候,发现定义成numericsimple类型,并不能起到回溯作用,但是在这里也能回搠,原因是在函数外部调用这个值,传入一个带有回溯性质的变量时,simple类型会自动变换成序列类型。

    【小结】:函数的调用时,传值与bar之间是绑定关系。不论是否定义为simple或者series类型,如果传值性质改变,函数接收时的参数定义也会变化。为方便起见,最好明确是simple类型或series,这样会更加清晰

    第四节:Array后缀参数类型

    # 示例1

    //func
    
    input: num1[x,y](numericarray), num2[w](numericarray);
    
    print("func ,","num1[1,3]=",num1[1,3],",num1[1,3][1]=",num1[1,3][1],",num2[2]=",num2[2],",num2[w]=",num2[w]);
    
    //sign
    
    array: arr0[3,4](0), arr1[5](0);
    
    arr0[1,3]=currentbar;
    
    arr1[2]=currentbar;
    
    print("sign ,","currentbar=",currentbar);
    
    func(arr0,arr1);
    
    //print输出
    
    sign ,currentbar=   3.00
    
    func ,num1[1,3]=   3.00,num1[1,3][1]=   2.00,num2[2]=   3.00,num2[w]=   0.00
    
    sign ,currentbar=   4.00
    
    func ,num1[1,3]=   4.00,num1[1,3][1]=   3.00,num2[2]=   4.00,num2[w]=   0.00

    # 说明:array类型参数也是非常简单的,略有一些不同是,最好在声明时预留出可以表示参数尺寸的位置。

    第五节:引用型参数

    5.1 通过传值改变传入参数的值

    # 示例1

    //func
    
    input: num0(numericref);
    
    num0=num0+1;
    
    //indicator
    
    var: var0(0);
    
    var0=var0+1;
    
    print("3 sign ,","currentbar=",currentbar,",var0=",var0);
    
    func(var0);
    
    print("5 sign ,","currentbar=",currentbar,",var0=",var0);
    
    //print输出结果
    
    3 sign ,currentbar=   1.00,var0=   1.00
    
    5 sign ,currentbar=   1.00,var0=   2.00
    
    
    3 sign ,currentbar=   2.00,var0=   3.00
    
    5 sign ,currentbar=   2.00,var0=   4.00
    
    
    3 sign ,currentbar=   3.00,var0=   5.00
    
    5 sign ,currentbar=   3.00,var0=   6.00

    # 说明:在这个例子中,打印了两遍var0的值,发现在调用函数后,在函数内部又改变了一次var0的值,我们知道,可以通过变量来计算某某值,在这里传入的参数也起到了和变量相同的作用,也改变了其传入的值。

    第六节:单一返回值与多个返回值

      如果记得之前学过想这样的函数,比如:value1 = Xaverage(close,5);通过Xaverage这个函数,传入close价格和周期5,然后用变量value1接收这个函数计算的值。这叫输入N个参数,返回一个计算好的值。

      现在有这么一个问题,我们能不能通过传入N个参数,返回N个返回的值呢?这里就用到了第五节中讲到的引用参数的用法。

    # 示例

    //函数:TrueFalse返回值
    Input:var0(NumericSimple),var1(Numericref),var2(Numericref);
    
    
    if currentbar = 1 then 
        begin
            var1 = 0;
            var2 = 0;
        end
    else
        begin
            var1 = var1 + var0;
            var2 = var1 - var0;
        end;
    
    //指标:
    var:var0(100),var1(0),var2(0);
    
    funbool(var0,var1,var2);
    print(var1," ",var2);
    
    //返回值:
       0.00    0.00
     100.00    0.00
     200.00  100.00
     300.00  200.00
     400.00  300.00
     500.00  400.00
     600.00  500.00
     700.00  600.00
     800.00  700.00
     900.00  800.00
    1000.00  900.00
    .... ..略

    # 说明:在这里我们建立一个TrueFalse的函数,默认返回值是False,当然我们不需要接收这个返回值,我们在这里通过把传参var1和var2当做变量传递给我们的函数。我们直接调用这两个“参数”,此时这两个变量在函数体内部经过运算,当做变量值反向传递给函数。这就实现了多个返回值的效果。

    =================================================

    之前的文章感谢大家的转载,希望转载时请注明出处,本人转自其它网站的图表一并感谢,谢谢~!

    https://www.cnblogs.com/noah0532/

  • 相关阅读:
    C#如何生成随机不重复的数字
    MVC学习笔记3 认识Routing
    认识Selenium简单介绍
    程序员为什么不写单元测试?
    MVC学习笔记4 认识View和Controller
    认识Selenium Selenium RC 使用介绍
    数据结构笔记5 队列
    数据结构笔记1 绪论 概念
    MVC学习笔记1 MVC概述
    数据结构笔记2 线性表之顺序表
  • 原文地址:https://www.cnblogs.com/noah0532/p/13682369.html
Copyright © 2011-2022 走看看