(1)概要
(2)plot関数
(3)change関数・iff関数
(4)input関数
(5)security関数、相関係数インジケータ
(6)fill関数
(7)bgcolor関数
(8)複数行を一括でコメントアウトできる?
(9)line.new関数・line.set関数、ピボット・インジケータ
(10)関数宣言(カスタム関数)、ピボット・ハイ・ロー・インジケータ
(11)ジグザグ(ZigZag)インジケータ
(12)平均足バー・マルチタイムフレーム(MTF)
(13)ストラテジー・バックテストの概要
(14)ストラテジー・サンプル「EMAクロス+固定TP/SL」
(15)ストラテジーの「最適化」をめぐるTradingViewとMetaTraderの違い
(16)Security関数のgapsとlookaheadとは?
(17)アラート条件の設定:alertcondition
はじめに
今回はPineScript入門ガイドの11回目です。前回は、ユーザー独自の関数宣言(カスタム関数、ユーザー定義関数)を使ってピボット・ハイ・ロー・インジケータを作りました。
今回は上記のピボット・ハイ・ローのロジックを応用して、人気のあるジグザグ(ZigZag)インジケータのサンプルを紹介します。このサンプルスクリプトは、前回同様、以下のTradingViewリファレンス・マニュアルに記載されているものです。

このジグザグ(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関数で描画・ライン更新をくりかえしていきます。






















