スポンサーリンク

Pine Script(Pineスクリプト)入門解説(11)ジグザグ(ZigZag)インジケータ

はじめに

今回はPineScript入門ガイドの11回目です。前回は、ユーザー独自の関数宣言(カスタム関数、ユーザー定義関数)を使ってピボット・ハイ・ロー・インジケータを作りました。

今回は上記のピボット・ハイ・ローのロジックを応用して、人気のあるジグザグ(ZigZag)インジケータのサンプルを紹介します。このサンプルスクリプトは、前回同様、以下のTradingViewリファレンス・マニュアルに記載されているものです。

Drawings — Pine Script User Manual 4 documentation

このジグザグ(ZigZag)インジケータのサンプルでは、ピボット・ハイ・ロー、変動率、ライン描画関連の関数、カスタム関数の宣言、条件分岐、複数のライン描画を繰り返す場合の変数の持ち方など、ノウハウをたくさん学ぶことができます。

ジグザグ(ZigZag)インジケータのスクリプト

それでは、ジグザグ・インジケータのサンプル・スクリプトを一行づつ説明していきます。
まず、このインジケータをチャートに表示させた結果は、以下の通りです。

このインジケータのスクリプトは、以下の通りです。
説明のために、(A)から(N)までの注釈を加えています。

//@version=4
study("Zig Zag", overlay=true)

dev_threshold = input(title="Deviation (%)", type=input.float, defval=5, 
 minval=1, maxval=100)
depth = input(title="Depth", type=input.integer, defval=10, minval=1) //-----(A)

pivots(src, length, isHigh) => //-----(B)
    p = nz(src[length])

    if length == 0
        [bar_index, p]
    else
        isFound = true
        for i = 0 to length - 1
            if isHigh and src[i] > p
                isFound := false
            if not isHigh and src[i] < p 
                isFound := false 

        for i = length + 1 to 2 * length 
            if isHigh and src[i] >= p
                isFound := false
            if not isHigh and src[i] <= p
                isFound := false

        if isFound and length * 2 <= bar_index //-----(C)
            [bar_index[length], p] 
        else 
            [int(na), float(na)] 

[iH, pH] = pivots(high, floor(depth / 2), true) //-----(D)
[iL, pL] = pivots(low, floor(depth / 2), false) 

calc_dev(base_price, price) => //-----(E)
    100 * (price - base_price) / base_price

var line lineLast = na //----(F)
var int iLast = 0
var float pLast = 0
var bool isHighLast = true // otherwise the last pivot is a low pivot
var int linesCount = 0

pivotFound(dev, isHigh, index, price) => //-----(G)
    if isHighLast == isHigh and not na(lineLast)
        // same direction
        if isHighLast ? price > pLast : price < pLast //----(H)
            if linesCount <= 1 
                line.set_xy1(lineLast, index, price) 
                line.set_xy2(lineLast, index, price) 
                [lineLast, isHighLast, false] 
            else 
                [line(na), bool(na), false] 
        else // reverse the direction (or create the very first line) -----(I)
            if na(lineLast) 
                id = line.new(index, price, index, price, color=color.red, width=2) 
                [id, isHigh, true] 
            else // price move is significant 
            if abs(dev) >= dev_threshold
                id = line.new(iLast, pLast, index, price, color=color.red, width=2)
                [id, isHigh, true]
            else
                [line(na), bool(na), false]

if not na(iH) and not na(iL) and iH == iL //-----(J)
    dev1 = calc_dev(pLast, pH) //-----(K)
    [id2, isHigh2, isNew2] = pivotFound(dev1, true, iH, pH) //-----(L)
    if isNew2
        linesCount := linesCount + 1 
    if not na(id2)
        lineLast := id2
        isHighLast := isHigh2
        iLast := iH
        pLast := pH

    dev2 = calc_dev(pLast, pL)
    [id1, isHigh1, isNew1] = pivotFound(dev2, false, iL, pL)
    if isNew1
        linesCount := linesCount + 1
    if not na(id1)
        lineLast := id1
        isHighLast := isHigh1
        iLast := iL
        pLast := pL

else
    if not na(iH) //-----(M)
        dev1 = calc_dev(pLast, pH)
        [id, isHigh, isNew] = pivotFound(dev1, true, iH, pH)
        if isNew
            linesCount := linesCount + 1
        if not na(id)
            lineLast := id
            isHighLast := isHigh
            iLast := iH
            pLast := pH
    else
        if not na(iL) //-----(N)
            dev2 = calc_dev(pLast, pL)
            [id, isHigh, isNew] = pivotFound(dev2, false, iL, pL)
            if isNew
                linesCount := linesCount + 1
            if not na(id)
                lineLast := id
                isHighLast := isHigh
                iLast := iL
                pLast := pL

(A) dev_threshold = input(title=”Deviation (%)”, type=input.float, defval=5, minval=1, maxval=100) depth = input(title=”Depth”, type=input.integer, defval=10, minval=1)

ジグザグ・インジケータの入力項目として、「dev_threshold」(初期値は5)と「depth」(初期値は10)を設定します。

「depth」は、ジグザグの山・谷の大きさの条件です。この数値を小さくすることで、ジグザグの山・谷が小さく細かくなります。「deviation」は、直前のラインから何パーセント反転しているかの条件です。

 

(B) pivots(src, length, isHigh) =>
カスタム関数pivotsを宣言します。この関数は、[●,●](タプル)というかたちの2つの値を返します。

この行から、(c)の前の行までは、前回のサンプル「ピボット・ハイ・ロー」のロジックと同じなので、わかりやすいと思います。

(C) if isFound and length * 2 <= bar_index
特定期間に高値・安値が存在する場合は、[足の番号、(高値・安値の)値]を返します。
特定期間に高値・安値が存在しない場合は、[int型の変数、float型の変数]に変換した値を返します。

int型は整数用、float(単精度浮動小数点)型は小数用の変数です。

 

(D) [iH, pH] = pivots(high, floor(depth / 2), true)
上記で宣言したPivot関数で、引数srcはhigh(高値)、引数lengthは「floor(depth / 2)」、引数isHighはTrue(高値判定)として、ピボット・ハイまたはピボット・ローの足の番号と値を返します。返した値は、変数[iH, pH]に格納します。

floor関数は、「指定された数値以下の最大の整数」を返します。

(E) calc_dev(base_price, price) =>
カスタム関数calc_devを宣言します。この関数は、「(現在値ー基準値) / 基準値 * 100」(=変動率)の値を返します。

ここまででスクリプトの前半が終了です。長いですが、頑張りましょう!

(F) var line lineLast = na
ここから5行は変数を宣言します。
var line lineLast = na:最終ライン。初期値は無し。
var int iLast = 0:前回の足の番号。初期値はゼロ。
var float pLast = 0:前回の値。初期値はゼロ。
var bool isHighLast = true:前回ピボットが高値か否か。falseなら前回が安値という意味です。
var int linesCount = 0:ラインの数。初期値はゼロ。

(G) pivotFound(dev, isHigh, index, price) =>
カスタム関数pivotFoundを宣言します。この関数は、dev(反転率)、 isHigh(高値か安値か)、 index(上記Pivot関数で返した足の番号)、price(上記Pivot関数で返した値)の4つの引数を使って、[ラインのid番号, 高値か否か, 新規か否か]を返します。

このpivotFound関数が、このジグザグ・インジケータの肝の部分です。ピボット・ハイ・ローの中で条件に合致した足と値を基点にして、ラインを描画して、次のライン描画のために必要な値を返します。

(H) if isHighLast ? price > pLast : price < pLast
トレンドが継続中のケースです。
前回ピボットが高値の場合は「もし現在値>前回高値ピボットの値ならば」
前回ピボットが安値の場合は「もし現在値<前回安値ピボットの値ならば」

linesCountが1以下の場合は、ライン設定を始点・終点ともに(今回の足の番号、今回の値)と設定します。
それ以外は、[line(na), bool(na), false]を返します。

lineCountが0の時はラインが全くなし、lineCountが1の時は「点」、lineCountが2以上になると「ライン」になります。

(I) else
トレンドが反転したケースです。

ラインがない場合は、新規ラインを設定します。このラインの始点・終点はともに(今回の足の番号、今回の値)ですので、この時点では「ライン」ではなく「点」です。
ラインがあって反転率を超えた場合に、新規のラインを設定します。このラインの始点は(前回の足の番号、前回の値)で、ラインの終点は(今回の足の番号、今回の値)とします。

(J) if not na(iH) and not na(iL) and iH == iL
iHの足が存在して、iLの足が存在して、且つiHとiLが同じ足の場合
ピボット・ハイとピボット・ローが同じ足で存在するというケースです。

わかりにくいですが、経済指標の発表などで上下にスパイクした場合に起こりえます。下のチャート例をご覧ください。

(K) dev1 = calc_dev(pLast, pH)
今回のピボット・ハイが、前回のピボット(高値または安値)からどれだけ変動したかを、(E)で宣言した calc_dev関数で求めます。

(L) [id2, isHigh2, isNew2] = pivotFound(dev1, true, iH, pH)
(G)で宣言したpivotFound関数で、((K)の変動率、高値、今回のピボットハイのバーの番号、今回のピボットハイの値)を引数として、[ラインid、高値であるか、新規のラインであるか]を返して、必要な場合にラインを描画します。
新規のラインであれば、ラインカウント(ラインの数)を1増やします。
ラインを描画した場合は、最終ラインをこのラインidに設定し、前回ピボットが高値であることを設定し、前回ピボットの足に今回の足の番号を設定し、前回ピボットの値に今回の値を設定します。

(M) if not na(iH)
(N) if not na(iL)
それぞれ、ピボット・ハイの足がある場合、ピボット・ローの足がある場合です。

あとは、(K)と(L)のロジックの繰り返し、すなわち変動率を出してpivotFound関数で描画・ライン更新をくりかえしていきます。

タイトルとURLをコピーしました