大家好,本节课我们要讲述的内容为Pine语言语法结构的最后一块拼图–条件和循环结构。假设通过你在期货市场上通过多年的学习,形成了一套完整的指标信号计算方法,和使用指标信号进行期货市场进场出场的判断方法,但是这套交易方法是基于手工操作的,大量的准确的指标运算和交易判断方法需要耗费你极大的精神成本,如果有一套代码可以胜任这项工作,仅仅需要你少量的精力去学习,可以大大减轻你的时间压力和工作压力,如此性价比的投入,你愿意尝试一下吗?
上节课的内容我们学习了运算符,可以帮助你进行准确的指标计算。本节课我们所学的内容是条件和循环结构,通过学习本节内容,可以帮助你利用指标进行交易逻辑的判断。在学完本节内容后,基本上Pine语言交易逻辑的梳理和代码的编写工作你都可以胜任了。
Pine语言中的条件结构是 if 和 switch。它们可用于:
if语言相信大家都很熟悉,“如果,就”。在if条件里准确的对信号加以描述,模型就可以执行相应的操作。其基本语法结构为:
if condition1 \\conditon后不需要加任何符号
action1
if condition1
action1
else
action2
if condition1
action1
else if condition2
action2
else
action3
if语句可用来给变量赋值或者执行逻辑操作,下面给大家举例示范下:
\\ 赋值
x = if close > close[1]
'涨'
else if close == close[1]
'平'
else
'跌'
runtime.log(x)
\\ 操作
if close > close[1]
runtime.log('涨')
else if close == close[1]
runtime.log('平')
else
runtime.log('跌')
需要注意的是:
x = if close > open
close
runtime.log('x:',x)
switch可以来说是if语句的另外一种呈现形式。switch也可以用来赋值或者进行逻辑操作。一般来说switch语句之后的分支条件必须是互斥的。就是说各分支的条件不能同时成立。因为switch只能执行一个分支的本地代码块。
switch的每个分支都可以写一个本地代码块,这个本地代码块的最后一行即为返回值(它可以是一个值的元组)。如果没有任何分支被的本地代码块被执行,则返回na。
switch结构中的表达式判断位置,可以写字符串、变量、表达式或函数调用。变量indic的值就为一个字符串,变量indic作为switch的表达式(可以是变量、函数调用、表达式),来确定执行switch中的哪个分支。如果变量func无法和switch中的任一个分支上的表达式匹配(即相等),则执行默认的分支代码块,会执行runtime.error(“error”)函数导致策略抛出异常停止。
indic = input('close', title="指标名称", tooltip="选择要使用的指标函数名称", options=['close', 'open', 'high', 'low', 'null'])
switch indic
'close' =>
runtime.log('收盘价:', close)
'open' =>
runtime.log('开盘价:', open)
'high' =>
runtime.log('最高价:', high)
'low' =>
runtime.log('最低价:', low)
=>
runtime.error('没有指标')
接下来我们看switch的另一种使用方式,即不带表达式的写法。
up = close > open
down = close < open
switch
up =>
runtime.log('涨')
down =>
runtime.log('跌')
测试代码例子就可以看到,switch会匹配执行分支条件上为真的本地代码块。一般来说switch语句之后的分支条件必须是互斥的。就是说例子中up和down不能同时为true。因为switch只能执行一个分支的本地代码块。除此之外还需要注意尽量不要把函数调用写在switch的分支中,函数无法在每个BAR上被调用可能引起一些数据计算的问题(除非如同「带有表达式的 switch」例子中,执行分支是确定的,在策略运行中是不会被更改的)。
请注意,在tradingview上,各个分支的返回值需要是一致的,比如统一的变量type类型(数字,字符,元组等),但是在优宽上没有明确的要求,可以根据需要设置需要的返回值,优宽实现了类型的兼容。
虽然Pine语言中有很多内置函数可以帮助我们进行循环的计算,但是循环的存在是有充分理由的,因为即使在 Pine 语言中,它们在某些情况下也是必需的。这些情况通常包括:
for语句使用非常简单。for语句之后跟随一个「计数」变量用于控制循环次数、引用其它值等,「计数」变量在循环开始之前被赋值为「初始计数」,然后根据「步长」设置递增,当「计数」变量大于「最终计数」时循环停止。for循环可以最终返回一个值(或者返回多个值,以[a, b, c]这样的形式),或者进行循环的操作。
for 起始计数 to 最终计数 by 步长 //优宽暂时不支持反向操作
语句 // 注释:语句里可以有break、continue
操作
x = for 起始计数 to 最终计数 by 步长
语句
返回值//循坏过后最终的值
下面举例示范下:
//操作
for i = 0 to 10
runtime.log("i:", i)
runtime.error("stop")
//赋值
ret = for i = 0 to 10
runtime.log("i:", i)
i // 如果这行不写,就返回空值,因为没有可返回的变量
runtime.log("ret:", ret)
runtime.error("stop")
在if语句中是可以插入break(跳出整个循环)这个循环和continue(跳过本次条件)。
for i = 0 to 10
runtime.log("i:", i)
if i == 3
break
for i = 0 to 10
runtime.log("i:", i)
if i == 3
continue
for.in语句主要针对对象为数组,主要有以下两种形式:
for 数组元素 in 数组
语句 // 注释:语句里可以有break,continue
for [索引变量, 索引变量对应的数组元素] in 数组
语句 // 注释:语句里可以有break,continue
可以看到两种形式的主要差别就在于for关键字之后跟随的内容,一种是使用一个变量作为引用数组元素的变量。一种是使用一个包含索引变量,数组元素变量的元组的结构来引用[索引i, 元素ele]。其它的返回值规则,使用break、continue等规则和for循环一致。我们也通过一个简单的例子来说明使用。
testArray = array.from(10, 20, 30, 40, 50, 60, 70, 80, 90, 100)
for ele in testArray
runtime.log("ele:", ele)
runtime.error("stop")
for [i, ele] in testArray
runtime.log("ele:", ele, ", i:", i)
runtime.error("stop")
while语句让循环部分的代码一直执行,直到while结构中的判断条件为假(false)。和if语句一致,while语句也可以进行赋值或者逻辑操作,while语句的基本结构为
while 判断条件
操作 // 注释:语句里可以有break,continue
返回值 = while 判断条件
语句 // 注释:语句里可以有break,continue
语句 // 注释:最后一条语句为返回值
while的其它规则和for循环类似,循环体本地代码块最后一行是返回值,可以返回多个值。当「循环条件」为真时执行循环,条件为假时停止循环。循环体中也可以使用break、continue语句。
i = 0
while i <= 10
runtime.log('i',i)
i += 1
runtime.error("stop")
x = while i <= 10
runtime.log('i',i)
i += 1
i//循环体结束后最后的值
runtime.log('x:',x)
runtime.error("stop")
Pine语言最后一块语法拼图已经讲解完毕,我们下节课再见。