發(fā)明者量化PINE語言入門教程-變量聲明、條件、循環(huán)結構
變量聲明
我們之前已經(jīng)學習過了“標識符”的概念,“標識符”就是作為變量的名稱來給變量命名的。所以也說:變量是保存值的標識符。那么如何聲明一個變量呢?聲明變量又有哪些規(guī)則?
聲明模式:
在聲明變量時最先寫的就是「聲明模式」,變量的聲明模式有三種即:
1、使用關鍵字var
。
2、使用關鍵字varip
。
3、什么都不寫。var
、varip
關鍵字其實我們在之前的「賦值運算符」章節(jié)已經(jīng)學習過了,這里不再贅述。如果變量的聲明模式什么都不寫,例如語句:i = 1
,其實我們之前也講過,這樣聲明的變量并且賦值,是在每個K線BAR上都執(zhí)行的。類型
FMZ上的Pine語言對于類型要求并不嚴苛,一般可以省略。不過為了兼容Trading View上的腳本策略,聲明變量時也是可以帶類型的。例如:
在Trading View上的類型是要求比較嚴苛的,如果使用以下代碼在Trading View上則會報錯:
標識符
標識符即變量名稱,標識符的命名在之前章節(jié)已經(jīng)講過,可以回看:https://www.fmz.com/bbs-topic/9390#標識符
總結一下,聲明一個變量可以寫作:
這里使用賦值運算符:=
在變量聲明時給變量賦值。賦值時,值可以是字符串、數(shù)值、表達式、函數(shù)調用、if
、?for
、while
或switch
等結構(這些結構關鍵字、語句用法我們后續(xù)課程中會詳細講解,其實我們已經(jīng)在之前的課程里學會了簡單的if語句賦值,可以回顧看看)。
這里我們著重講解一下input函數(shù),這個函數(shù)是我們在設計編寫策略時會很頻繁用到的一個函數(shù)。也是設計策略時非常關鍵的函數(shù)。
input函數(shù):
在FMZ上的input函數(shù)和在Trading View上的有些不同,不過該函數(shù)都是作為策略參數(shù)的賦值輸入使用。下面我們來通過一個例子詳細說明input函數(shù)在FMZ上的使用:
在聲明變量時給變量賦值,經(jīng)常使用的就是input函數(shù),在FMZ上input函數(shù)會在FMZ策略界面自動畫出用于設置策略參數(shù)的控件。FMZ上支持的控件目前有數(shù)值輸入框、文本輸入框、下拉框、布爾值勾選。并且可以設置策略參數(shù)分組、設置參數(shù)的提示文本信息等功能。

我們介紹input函數(shù)的幾個主要參數(shù):
defval :作為input函數(shù)設置的策略參數(shù)選項的默認值,支持Pine語言的內置變量、數(shù)值、字符串
title :策略在實盤/回測的策略界面上顯示的參數(shù)名稱。
tooltip :策略參數(shù)的提示信息,當鼠標懸停在策略參數(shù)上會顯示出這個參數(shù)設置的文本信息。
group :策略參數(shù)分組名稱,可以給參數(shù)分組。
除了單獨的變量聲明、賦值,Pine語言中還有聲明一組變量并且賦值的寫法:
最常見的就是我們使用ta.macd
函數(shù)計算MACD指標時,由于MACD指標是一個多線的指標,計算出三組數(shù)據(jù)。所以就可以寫為:
我們使用以上代碼就很容易畫出MACD圖表,不止是內置函數(shù)可以返回多個變量,編寫的自定義函數(shù)也可以返回多個數(shù)據(jù)。
使用if等結構作為多個變量賦值的寫法也和上面的自定義函數(shù)方式類似,有興趣也可以試下。
條件結構
一些函數(shù)是無法寫在條件分支的本地代碼塊里的,主要有以下幾個函數(shù):
barcolor(), fill(), hline(), indicator(), plot(), plotcandle(), plotchar(), plotshape()
Trading View上會編譯報錯。FMZ上限制不是那么嚴苛,但是也建議遵循Trading View上的規(guī)范書寫。例如這樣雖然在FMZ上不報錯,不過不建議這樣寫。
if語句
講解例子:
重點:判斷用的表達式,返回布爾值。注意縮進。最多只能有一個else分支。所有分支表達式都不為真,也沒有else分支,則返回na。
由于當K線BAR為陰線時,即close < open時,if語句后的表達式為假(false),則不執(zhí)行if的本地代碼塊。這個時候也沒有else分支,if語句就返回了na。x被賦值為na。在畫圖上就無法畫出這個點,我們通過回測畫圖也可以觀察到。
switch語句
switch語句也是一種分支結構的語句,用來設計根據(jù)某些條件執(zhí)行不同的路徑。switch語句一般來說有以下幾個關鍵知識點。
1、switch語句和if語句一樣,也可以返回值。
2、和其它語言中的switch語句不一樣,執(zhí)行switch結構時,只執(zhí)行其代碼中的一個本地塊,所以break聲明是不必要的(即不需要寫break之類的關鍵字)。
3、switch的每個分支都可以寫一個本地代碼塊,這個本地代碼塊的最后一行即為返回值(它可以是一個值的元組)。如果沒有任何分支被的本地代碼塊被執(zhí)行,則返回na。
4、switch結構中的表達式判斷位置,可以寫字符串、變量、表達式或函數(shù)調用。
5、switch允許指定一個返回值,該值作為結構中沒有其它情況執(zhí)行時使用的默認值。
switch分為兩種形式,我們逐一來看例子,了解其用法。
1、帶有表達式的?switch
?,例子講解:
之前我們學習了input函數(shù),這里我們繼續(xù)學習兩個和input類似的函數(shù):input.string
、input.int
函數(shù)。input.string
用來返回字符串,input.int
函數(shù)用來返回整型數(shù)值。例子中其實就新增了一個options
參數(shù)的用法,options
參數(shù)可以傳入一個可選值組成的數(shù)組。例如例子中的options=["EMA", "SMA", "RMA", "WMA"]
和options=[5, 10, 20]
(注意一個是字符串類型,一個是數(shù)值類型)。這樣策略界面上的控件就不是需要輸入具體數(shù)值了,而是控件變?yōu)橄吕?,選擇options參數(shù)中提供的這些選項。
變量func的值就為一個字符串,變量func作為switch的表達式(可以是變量、函數(shù)調用、表達式),來確定執(zhí)行switch中的哪個分支。如果變量func無法和switch中的任一個分支上的表達式匹配(即相等),則執(zhí)行默認的分支代碼塊,會執(zhí)行runtime.error("error")
函數(shù)導致策略拋出異常停止。
我們上面的測試代碼中在switch的默認分支代碼塊的最后一行runtime.error之后,我們并沒有加入[na, na]這樣的代碼來兼容返回值,在trading view上是需要考慮該問題的,如果類型不一致會報錯。但是在FMZ上由于沒有嚴格要求類型,所以是可以省略這種兼容代碼的。所以在FMZ上不用考慮if、switch分支返回值的類型兼容問題。
在FMZ上不會報錯,在trading view上會報錯。因為if分支返回的類型不一致。
2、沒有表達式的switch
接下來我們看switch
的另一種使用方式,即不帶表達式的寫法。
測試代碼例子就可以看到,switch會匹配執(zhí)行分支條件上為真的本地代碼塊。一般來說switch語句之后的分支條件必須是互斥的。就是說例子中up和down不能同時為true。因為switch只能執(zhí)行一個分支的本地代碼塊,有興趣可以把代碼中這行語句:up = close > open // up = close < open?
更換成注釋里的內容,回測觀察下結果。會發(fā)現(xiàn)switch分支只能執(zhí)行第一個分支。除此之外還需要注意盡量不要把函數(shù)調用寫在switch的分支中,函數(shù)無法在每個BAR上被調用可能引起一些數(shù)據(jù)計算的問題(除非如同「帶有表達式的?switch
」例子中,執(zhí)行分支是確定的,在策略運行中是不會被更改的)。
循環(huán)結構
for語句
for語句使用非常簡單,for循環(huán)可以最終返回一個值(或者返回多個值,以[a, b, c]這樣的形式)。如同以上偽代碼中賦值給「返回值」位置的變量。for語句之后跟隨一個「計數(shù)」變量用于控制循環(huán)次數(shù)、引用其它值等?!赣嫈?shù)」變量在循環(huán)開始之前被賦值為「初始計數(shù)」,然后根據(jù)「步長」設置遞增,當「計數(shù)」變量大于「最終計數(shù)」時循環(huán)停止。
for循環(huán)中使用的break
關鍵字:當執(zhí)行了break
語句后,循環(huán)就停止了。
for循環(huán)中使用的continue
關鍵字:當執(zhí)行了continue
語句后,循環(huán)會忽略continue
之后的代碼,直接執(zhí)行下一輪循環(huán)。for語句返回最后一次循環(huán)執(zhí)行時的返回值。如果沒有任何代碼執(zhí)行則返回空值。
下面我們用一個簡單例子來展示:
for ... in 語句
for ... in
語句有兩種形式,以下面的偽代碼來說明。
可以看到兩種形式的主要差別就在于for關鍵字之后跟隨的內容,一種是使用一個變量作為引用數(shù)組元素的變量。一種是使用一個包含索引變量,數(shù)組元素變量的元組的結構來引用。其它的返回值規(guī)則,使用break、continue等規(guī)則和for循環(huán)一致。我們也通過一個簡單的例子來說明使用。
當需要使用索引時,就使用for [i, ele] in testArray
的寫法。
for循環(huán)應用
當可以使用Pine語言提供的內置函數(shù)完成一些循環(huán)邏輯計算時,可以使用循環(huán)結構直接編寫,也可以使用內置函數(shù)處理。我們舉兩個例子。
1、計算均值
使用循環(huán)結構設計時:
例子中使用了for循環(huán)求和,然后計算均值。
直接使用內置函數(shù)計算均線:
直接使用內置函數(shù)ta.sma
,計算均線指標,顯然對于計算均線使用內置函數(shù)更加簡單。在圖表上對比可以看到計算出的結果完全一致。
2、求和
還是使用上面的例子來說明。
使用循環(huán)結構設計時:
對于計算數(shù)組所有的元素的和可以使用循環(huán)來處理,也可以使用內置函數(shù)array.sum
來計算。
直接使用內置函數(shù)計算求和:
可以看到算出的數(shù)據(jù),使用plot畫在圖表上顯示完全一致。
那既然用內置函數(shù)就可以完成這些工作,為什么還要設計循環(huán)?使用循環(huán)主要是基于這3點的應用:
1、對于數(shù)組的一些操作、計算。
2、回顧歷史,例如,找出有多少過去的高點高于當前BAR的高點。由于當前BAR的高 點僅在腳本運行的BAR上已知,因此需要一個循環(huán)來及時返回并分析過去的BAR。
3、使用Pine語言的內置函數(shù)無法完成對過去BAR的計算的情況。
while 語句
while
語句讓循環(huán)部分的代碼一直執(zhí)行,直到while結構中的判斷條件為假(false)。
while的其它規(guī)則和for循環(huán)類似,循環(huán)體本地代碼塊最后一行是返回值,可以返回多個值。當「循環(huán)條件」為真時執(zhí)行循環(huán),條件為假時停止循環(huán)。循環(huán)體中也可以使用break、continue語句。
我還是用計算均線的例子來演示:
可以看到while循環(huán)使用也是非常簡單的,還可以設計一些計算邏輯是無法用內置函數(shù)代替的,例如計算階乘: